Support jpkl executable for Windows (#872)

This updates the script used to start the executable to support
Windows as well.

For Windows support, the executable needs to be named `jpkl.bat`.
This commit is contained in:
Daniel Chao
2025-01-14 05:16:59 -08:00
committed by GitHub
parent 3296dd8a89
commit 100dd0560e
3 changed files with 44 additions and 16 deletions

View File

@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 import org.gradle.api.tasks.TaskAction
/** /**
* Builds a self-contained Pkl CLI Jar that is directly executable on *nix and executable with `java * Builds a self-contained Pkl CLI Jar that is directly executable on Windows, macOS, and Linux.
* -jar` on Windows.
* *
* For direct execution, the `java` command must be on the PATH. * 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() { abstract class ExecutableJar : DefaultTask() {
@get:InputFile abstract val inJar: RegularFileProperty @get:InputFile abstract val inJar: RegularFileProperty
@@ -41,12 +40,27 @@ abstract class ExecutableJar : DefaultTask() {
val inFile = inJar.get().asFile val inFile = inJar.get().asFile
val outFile = outJar.get().asFile val outFile = outJar.get().asFile
val escapedJvmArgs = jvmArgs.get().joinToString(separator = " ") { "\"$it\"" } val escapedJvmArgs = jvmArgs.get().joinToString(separator = " ") { "\"$it\"" }
val startScript = val unixStartScript =
""" """
#!/bin/sh @ 2>/dev/null # 2>nul & echo off & goto BOF
exec java $escapedJvmArgs -jar $0 "$@" :
""" exec java $escapedJvmArgs -jar "$0" "$@"
.trimIndent() + "\n\n\n" 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 -> outFile.outputStream().use { outStream ->
startScript.byteInputStream().use { it.copyTo(outStream) } startScript.byteInputStream().use { it.copyTo(outStream) }
inFile.inputStream().use { it.copyTo(outStream) } inFile.inputStream().use { it.copyTo(outStream) }

View File

@@ -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. 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, However, it requires a Java 17 (or higher) runtime on the system path, and has a noticeable startup delay.
and runs complex Pkl code slower than the native executables.
All flavors are built from the same codebase and undergo the same automated testing. 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. 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]]
=== 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] [source,shell]
[subs="+attributes"] [subs="+attributes"]
---- ----
@@ -209,6 +216,16 @@ chmod +x jpkl
./jpkl --version ./jpkl --version
---- ----
Windows::
+
[source,PowerShell]
[subs="+attributes"]
----
Invoke-WebRequest '{uri-pkl-java-download}' -OutFile jpkl.bat
.\jpkl --version
----
====
This should print something similar to: This should print something similar to:
[source,shell] [source,shell]
@@ -217,8 +234,7 @@ This should print something similar to:
Pkl {pkl-version} (macOS 14.2, Java 17.0.10) Pkl {pkl-version} (macOS 14.2, Java 17.0.10)
---- ----
NOTE: The Java executable does not work as an executable file on Windows. NOTE: The Java executable is named `jpkl`.
However, it will work as a jar, for example, with `java -jar jpkl`.
[[usage]] [[usage]]
== Usage == Usage
@@ -721,8 +737,6 @@ Type :help or :examples for more information.
pkl> pkl>
---- ----
NOTE: The Java executable is named `jpkl`.
=== Loading Modules === Loading Modules
To load <<config.pkl,`config.pkl`>> into the REPL, run: To load <<config.pkl,`config.pkl`>> into the REPL, run:

View File

@@ -363,7 +363,7 @@ publishing {
description.set( description.set(
""" """
Pkl CLI executable for Java. 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 <path/to/jpkl>`.
Requires Java 17 or higher. Requires Java 17 or higher.
""" """
.trimIndent() .trimIndent()