Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
ajaychandran committed Dec 1, 2024
1 parent ef5bdfe commit 191f88f
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 151 deletions.
7 changes: 0 additions & 7 deletions .github/workflows/run-mill-action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ on:
install-android-sdk:
default: false
type: boolean
setup-msvc:
default: false
type: boolean
description: 'sets up Windows environment for compiling C/C++ code'

jobs:
run:
Expand All @@ -60,9 +56,6 @@ jobs:

- uses: coursier/cache-action@v6

- uses: ilammy/msvc-dev-cmd@v1
if: inputs.setup-msvc && startsWith(inputs.os, 'windows')

- uses: actions/setup-java@v4
with:
java-version: ${{ inputs.java-version }}
Expand Down
6 changes: 0 additions & 6 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,26 +135,20 @@ jobs:
# the whole suite can take hours on windows v.s. half an hour on linux
- java-version: '11'
millargs: '"{main,scalalib,bsp}.__.testCached"'
setup-msvc: false
- java-version: '11'
millargs: '"example.scalalib.basic.__.fork.testCached"'
setup-msvc: true # required by Graal VM native-image
- java-version: 17
millargs: "'integration.{feature,failure}[_].fork.testCached'"
setup-msvc: false
- java-version: '11'
millargs: "'integration.invalidation[_].server.testCached'"
setup-msvc: false
- java-version: '11'
millargs: "contrib.__.testCached"
setup-msvc: false

uses: ./.github/workflows/run-mill-action.yml
with:
os: windows-latest
java-version: ${{ matrix.java-version }}
millargs: ${{ matrix.millargs }}
setup-msvc: ${{ matrix.setup-msvc }}

itest:
needs: build-linux
Expand Down
99 changes: 32 additions & 67 deletions dist/package.mill
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import mill.api.JarManifest
import de.tobiasroeser.mill.vcs.version.VcsVersion
import $file.ci.upload

import java.nio.file.Paths
import scala.util.{Properties, Using}

// TODO remove nativeImage* tasks and extend NativeImageModule once available
// TODO extend NativeImageModule once available
object `package` extends RootModule with build.MillPublishJavaModule {

/**
Expand Down Expand Up @@ -348,83 +347,49 @@ object `package` extends RootModule with build.MillPublishJavaModule {
}
}

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

def native: T[PathRef] = Task {
val executable = Task.dest / "mill"
def nativeImage(args: String*): Command[PathRef] = Task.Command {
val dest = T.dest
val executableName = if (Properties.isWin) "mill.exe" else "mill"
val executable = Task.dest / executableName

Task.traverse(allPublishModules)(m => m.publishLocalCached)()
val assembly = super.assembly().path

val command = Seq.newBuilder[String]
.+=(nativeImageTool().path.toString)
.++=(Seq("-cp", assembly.toString))
// Workaround for Zinc/JNA bug
// https://github.com/sbt/sbt/blame/6718803ee6023ab041b045a6988fafcfae9d15b5/main/src/main/scala/sbt/Main.scala#L130
.+=("-Djna.nosys=true")
.+=("--no-fallback")
.++=(args)
.+=("mill.runner.client.MillClientMain")
.+=(executableName)
.result()
os.proc(command).call(cwd = dest, stdout = os.Inherit)

Using(os.write.outputStream(
executable,
if (Properties.isWin) null else "rwxrwxrwx",
createFolders = true)
) { out =>
// concatenate native image and assembly as prescribed in:
// https://github.com/com-lihaoyi/mill/issues/4007#issuecomment-2495933167
out.write(os.read.bytes(nativeImage().path))
// concatenate executable and assembly as prescribed in:
// https://github.com/com-lihaoyi/mill/issues/4007#issuecomment-2495933167
Using(os.write.append.outputStream(executable)) { out =>
out.write(System.lineSeparator.getBytes)
out.write(os.read.bytes(super.assembly().path))
out.write(os.read.bytes(assembly))
out.flush()
}

PathRef(executable)
}

def nativeImage: T[PathRef] = Task {
val dest = T.dest

val classPath = runClasspath().iterator
.map(_.path)
.mkString(java.io.File.pathSeparator)
val executableName = nativeImageExecutableName()

val command =
Seq.newBuilder[String]
.+=(nativeImageCli().path.toString)
.++=(Seq("--class-path", classPath))
.++=(nativeImageOptions())
.++=(Seq(finalMainClass(), executableName))
.result()

T.log.info(s"building native image $executableName")
os.proc(command).call(cwd = dest)

PathRef(dest / executableName)
}

def nativeImageCli: T[PathRef] = Task {
val ext = if (Properties.isWin) ".cmd" else ""
val path = zincWorker().javaHome() match {
case None =>
os.Path(Paths.get(s"native-image$ext").toAbsolutePath)
def nativeImageTool: T[PathRef] = Task {
zincWorker().javaHome().map(_.path)
.orElse(sys.env.get("GRAALVM_HOME").map(os.Path(_))) match {
case Some(home) =>
home.path / "bin" / s"native-image$ext"
val tool = if (Properties.isWin) "native-image.cmd" else "native-image"
val path = home / "bin" / tool
if (os.exists(path)) PathRef(path)
else throw new RuntimeException(s"$path not found")
case None =>
throw new RuntimeException("ZincWorkerModule.javaHome/GRAALVM_HOME not defined")
}
if (os.exists(path)) PathRef(path)
else throw new RuntimeException(s"native-image not found at $path")
}

def nativeImageExecutableName: T[String] = Task {
val name = finalMainClass().split('.').last
if (Properties.isWin) s"$name.exe" else name
}

def nativeImageOptions: T[Seq[String]] = Task {
val (millArgs, otherArgs) =
forkArgs().partition(arg => arg.startsWith("-DMILL") && !arg.startsWith("-DMILL_VERSION"))
// Pass Mill options via file, due to small max args limit in Windows
val vmOptionsFile = Task.dest / "mill.properties"
val millOptionsContent =
millArgs.map(_.drop(2).replace("\\", "/")).mkString(
"\r\n"
) // drop -D prefix, replace \ with /
os.write(vmOptionsFile, millOptionsContent)
Seq.newBuilder[String]
.+=("--no-fallback")
.+=(s"-DMILL_OPTIONS_PATH=$vmOptionsFile")
.++=(otherArgs)
.result()
}

def zincWorker = ModuleRef(ZincWorkerGraalvm)
Expand Down
13 changes: 5 additions & 8 deletions example/javalib/basic/7-native-image/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,22 @@ import mill.define.ModuleRef

object foo extends JavaModule with NativeImageModule {

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

def zincWorker = ModuleRef(ZincWorkerGraalvm)

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

// This example demonstrates how to build a native image for a Java application using https://www.graalvm.org/[Graal VM].
//
// - The `native-image` CLI is downloaded with a custom Java home.
//
// - The main class, `foo.HelloWorld` is auto detected by `NativeImageModule` using `finalMainClass`.
// 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.

/** Usage

> ./mill foo.nativeImage
GraalVM Native Image: Generating...App...
Finished generating...App...

> ./out/foo/nativeImage.dest/HelloWorld
> ./out/foo/nativeImage.dest/App
Hello, World!
*/
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package foo;

public class HelloWorld {
public class App {

public static void main(String[] args) {
System.out.println("Hello, World!");
Expand Down
17 changes: 7 additions & 10 deletions example/kotlinlib/basic/7-native-image/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,24 @@ import mill.define.ModuleRef

object foo extends KotlinModule with NativeImageModule {

def kotlinVersion = "1.9.24"

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

def zincWorker = ModuleRef(ZincWorkerGraalvm)

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

def kotlinVersion = "1.9.24"
}

// This example demonstrates how to build a native image for a Kotlin application using https://www.graalvm.org/[Graal VM].
//
// - The `native-image` CLI is downloaded with a custom Java home.
//
// - The main class, `foo.HelloWorld` is auto detected by `NativeImageModule` using `finalMainClass`.
// 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.

/** Usage

> ./mill foo.nativeImage
GraalVM Native Image: Generating...AppKt...
Finished generating...AppKt...

> ./out/foo/nativeImage.dest/HelloWorldKt
> ./out/foo/nativeImage.dest/AppKt
Hello, World!
*/
17 changes: 7 additions & 10 deletions example/scalalib/basic/7-native-image/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,24 @@ import mill.define.ModuleRef

object foo extends ScalaModule with NativeImageModule {

def scalaVersion = "2.13.11"

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

def zincWorker = ModuleRef(ZincWorkerGraalvm)

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

def scalaVersion = "2.13.11"
}

// This example demonstrates how to build a native image for a Scala application using https://www.graalvm.org/[Graal VM].
//
// - The `native-image` CLI is downloaded with a custom Java home.
//
// - The main class, `foo.HelloWorld` is auto detected by `NativeImageModule` using `finalMainClass`.
// 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.

/** Usage

> ./mill foo.nativeImage
GraalVM Native Image: Generating...App...
Finished generating...App...

> ./out/foo/nativeImage.dest/HelloWorld
> ./out/foo/nativeImage.dest/App
Hello, World!
*/
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package foo

object HelloWorld {
object App {

def main(args: Array[String]): Unit =
println("Hello, World!")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ public static LoadResult load() {
long startTime = System.currentTimeMillis();
Optional<Method> millMainMethod = Optional.empty();
try {
Class<?> millMainClass =
MillNoServerLauncher.class.getClassLoader().loadClass("mill.runner.MillMain");
Class<?> millMainClass = Class.forName("mill.runner.MillMain");
Method mainMethod = millMainClass.getMethod("main", String[].class);
millMainMethod = Optional.of(mainMethod);
} catch (ClassNotFoundException | NoSuchMethodException e) {
Expand Down
Loading

0 comments on commit 191f88f

Please sign in to comment.