diff --git a/buildSrc/src/main/kotlin/ExecutableJar.kt b/buildSrc/src/main/kotlin/ExecutableJar.kt index bb455de2..a558539f 100644 --- a/buildSrc/src/main/kotlin/ExecutableJar.kt +++ b/buildSrc/src/main/kotlin/ExecutableJar.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. + * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,12 +22,11 @@ import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction /** - * Builds a self-contained Pkl CLI Jar that is directly executable on *nix and executable with `java - * -jar` on Windows. + * Builds a self-contained Pkl CLI Jar that is directly executable on Windows, macOS, and Linux. * * For direct execution, the `java` command must be on the PATH. * - * https://skife.org/java/unix/2011/06/20/really_executable_jars.html + * Technique borrowed from [Mill](https://mill-build.org/blog/5-executable-jars.html). */ abstract class ExecutableJar : DefaultTask() { @get:InputFile abstract val inJar: RegularFileProperty @@ -41,12 +40,27 @@ abstract class ExecutableJar : DefaultTask() { val inFile = inJar.get().asFile val outFile = outJar.get().asFile val escapedJvmArgs = jvmArgs.get().joinToString(separator = " ") { "\"$it\"" } - val startScript = + val unixStartScript = """ - #!/bin/sh - exec java $escapedJvmArgs -jar $0 "$@" - """ - .trimIndent() + "\n\n\n" + @ 2>/dev/null # 2>nul & echo off & goto BOF + : + exec java $escapedJvmArgs -jar "$0" "$@" + exit + """ + .trimIndent() + val windowsStartScript = + """ + :BOF + setlocal + @echo off + java $escapedJvmArgs -jar "%~dpnx0" %* + endlocal + exit /B %errorlevel% + """ + .trimIndent() + // need crlf endings for Windows portion of script + .replace("\n", "\r\n") + val startScript = unixStartScript + "\r\n" + windowsStartScript + "\r\n".repeat(3) outFile.outputStream().use { outStream -> startScript.byteInputStream().use { it.copyTo(outStream) } inFile.inputStream().use { it.copyTo(outStream) } diff --git a/docs/modules/pkl-cli/pages/index.adoc b/docs/modules/pkl-cli/pages/index.adoc index ee34680d..ffdd6999 100644 --- a/docs/modules/pkl-cli/pages/index.adoc +++ b/docs/modules/pkl-cli/pages/index.adoc @@ -53,8 +53,7 @@ whereas, the Alpine Linux executable is statically linked against _musl libc_ an ==== The Java executable works on multiple platforms and has a smaller binary size than the native executables. -However, it requires a Java 17 (or higher) runtime on the system path, has a noticeable startup delay, -and runs complex Pkl code slower than the native executables. +However, it requires a Java 17 (or higher) runtime on the system path, and has a noticeable startup delay. All flavors are built from the same codebase and undergo the same automated testing. Except where noted otherwise, the rest of this page discusses the native executables. @@ -201,6 +200,14 @@ NOTE: We currently do not support the aarch64 architecture for Windows. [[java-executable]] === Java Executable +The Java executable is a jar that can be executed directly on macOS, Linux, and Windows. + +It requires `java` to be installed, and available on `$PATH`. + +[tabs] +==== +macOS/Linux:: ++ [source,shell] [subs="+attributes"] ---- @@ -209,6 +216,16 @@ chmod +x jpkl ./jpkl --version ---- +Windows:: ++ +[source,PowerShell] +[subs="+attributes"] +---- +Invoke-WebRequest '{uri-pkl-java-download}' -OutFile jpkl.bat +.\jpkl --version +---- +==== + This should print something similar to: [source,shell] @@ -217,8 +234,7 @@ This should print something similar to: Pkl {pkl-version} (macOS 14.2, Java 17.0.10) ---- -NOTE: The Java executable does not work as an executable file on Windows. -However, it will work as a jar, for example, with `java -jar jpkl`. +NOTE: The Java executable is named `jpkl`. [[usage]] == Usage @@ -721,8 +737,6 @@ Type :help or :examples for more information. pkl> ---- -NOTE: The Java executable is named `jpkl`. - === Loading Modules To load <> into the REPL, run: diff --git a/pkl-cli/pkl-cli.gradle.kts b/pkl-cli/pkl-cli.gradle.kts index 27967f1a..d597821c 100644 --- a/pkl-cli/pkl-cli.gradle.kts +++ b/pkl-cli/pkl-cli.gradle.kts @@ -363,7 +363,7 @@ publishing { description.set( """ Pkl CLI executable for Java. - Can be executed directly on *nix (if the `java` command is found on the PATH) and with `java -jar` otherwise. + Can be executed directly, or with `java -jar `. Requires Java 17 or higher. """ .trimIndent()