mirror of
https://github.com/apple/pkl.git
synced 2026-01-11 22:30:54 +01:00
342 lines
11 KiB
Kotlin
342 lines
11 KiB
Kotlin
/*
|
|
* Copyright © 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.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
import java.lang.Runtime.Version
|
|
import kotlin.io.path.createDirectories
|
|
import kotlin.io.path.writeText
|
|
import org.gradle.accessors.dm.LibrariesForLibs
|
|
|
|
plugins {
|
|
id("pklGraalVm")
|
|
id("pklJavaLibrary")
|
|
id("pklNativeLifecycle")
|
|
id("pklPublishLibrary")
|
|
id("com.gradleup.shadow")
|
|
}
|
|
|
|
// assumes that `pklJavaExecutable` is also applied
|
|
val executableSpec = project.extensions.getByType<ExecutableSpec>()
|
|
val buildInfo = project.extensions.getByType<BuildInfo>()
|
|
|
|
val stagedMacAmd64Executable: Configuration by configurations.creating
|
|
val stagedMacAarch64Executable: Configuration by configurations.creating
|
|
val stagedLinuxAmd64Executable: Configuration by configurations.creating
|
|
val stagedLinuxAarch64Executable: Configuration by configurations.creating
|
|
val stagedAlpineLinuxAmd64Executable: Configuration by configurations.creating
|
|
val stagedWindowsAmd64Executable: Configuration by configurations.creating
|
|
|
|
val nativeImageClasspath by
|
|
configurations.creating {
|
|
extendsFrom(configurations.runtimeClasspath.get())
|
|
// Ensure native-image version uses GraalVM C SDKs instead of Java FFI or JNA
|
|
// (comes from artifact `mordant-jvm-graal-ffi`).
|
|
exclude("com.github.ajalt.mordant", "mordant-jvm-ffm")
|
|
exclude("com.github.ajalt.mordant", "mordant-jvm-ffm-jvm")
|
|
exclude("com.github.ajalt.mordant", "mordant-jvm-jna")
|
|
exclude("com.github.ajalt.mordant", "mordant-jvm-jna-jvm")
|
|
}
|
|
|
|
val libs = the<LibrariesForLibs>()
|
|
|
|
dependencies {
|
|
fun executableFile(suffix: String) =
|
|
files(
|
|
layout.buildDirectory.dir("executable").map { dir ->
|
|
dir.file(executableSpec.name.map { "$it-$suffix" })
|
|
}
|
|
)
|
|
nativeImageClasspath(libs.truffleRuntime)
|
|
nativeImageClasspath(libs.graalSdk)
|
|
|
|
stagedMacAarch64Executable(executableFile("macos-aarch64"))
|
|
stagedMacAmd64Executable(executableFile("macos-amd64"))
|
|
stagedLinuxAmd64Executable(executableFile("linux-amd64"))
|
|
stagedLinuxAarch64Executable(executableFile("linux-aarch64"))
|
|
stagedAlpineLinuxAmd64Executable(executableFile("alpine-linux-amd64"))
|
|
stagedWindowsAmd64Executable(executableFile("windows-amd64.exe"))
|
|
}
|
|
|
|
private fun NativeImageBuild.amd64() {
|
|
arch = Architecture.AMD64
|
|
dependsOn(":installGraalVmAmd64")
|
|
}
|
|
|
|
private fun NativeImageBuild.aarch64() {
|
|
arch = Architecture.AARCH64
|
|
dependsOn(":installGraalVmAarch64")
|
|
}
|
|
|
|
private fun NativeImageBuild.setClasspath() {
|
|
classpath.from(sourceSets.main.map { it.output })
|
|
classpath.from(
|
|
project(":pkl-commons-cli").extensions.getByType(SourceSetContainer::class)["svm"].output
|
|
)
|
|
classpath.from(nativeImageClasspath)
|
|
}
|
|
|
|
val macExecutableAmd64 by
|
|
tasks.registering(NativeImageBuild::class) {
|
|
imageName = executableSpec.name.map { "$it-macos-amd64" }
|
|
mainClass = executableSpec.mainClass
|
|
amd64()
|
|
setClasspath()
|
|
}
|
|
|
|
val macExecutableAarch64 by
|
|
tasks.registering(NativeImageBuild::class) {
|
|
imageName = executableSpec.name.map { "$it-macos-aarch64" }
|
|
mainClass = executableSpec.mainClass
|
|
aarch64()
|
|
setClasspath()
|
|
}
|
|
|
|
val linuxExecutableAmd64 by
|
|
tasks.registering(NativeImageBuild::class) {
|
|
imageName = executableSpec.name.map { "$it-linux-amd64" }
|
|
mainClass = executableSpec.mainClass
|
|
amd64()
|
|
setClasspath()
|
|
}
|
|
|
|
val linuxExecutableAarch64 by
|
|
tasks.registering(NativeImageBuild::class) {
|
|
imageName = executableSpec.name.map { "$it-linux-aarch64" }
|
|
mainClass = executableSpec.mainClass
|
|
aarch64()
|
|
setClasspath()
|
|
// Ensure compatibility for kernels with page size set to 4k, 16k and 64k
|
|
// (e.g. Raspberry Pi 5, Asahi Linux)
|
|
extraNativeImageArgs.add("-H:PageSize=65536")
|
|
}
|
|
|
|
val alpineExecutableAmd64 by
|
|
tasks.registering(NativeImageBuild::class) {
|
|
imageName = executableSpec.name.map { "$it-alpine-linux-amd64" }
|
|
mainClass = executableSpec.mainClass
|
|
amd64()
|
|
setClasspath()
|
|
extraNativeImageArgs.addAll(listOf("--static", "--libc=musl"))
|
|
}
|
|
|
|
val windowsExecutableAmd64 by
|
|
tasks.registering(NativeImageBuild::class) {
|
|
imageName = executableSpec.name.map { "$it-windows-amd64" }
|
|
mainClass = executableSpec.mainClass
|
|
amd64()
|
|
setClasspath()
|
|
}
|
|
|
|
val assembleNative by tasks.existing
|
|
|
|
val testStartNativeExecutable by
|
|
tasks.registering {
|
|
dependsOn(assembleNative)
|
|
|
|
// dummy file for up-to-date checking
|
|
val outputFile = project.layout.buildDirectory.file("testStartNativeExecutable/output.txt")
|
|
outputs.file(outputFile)
|
|
|
|
val execOutput =
|
|
providers.exec { commandLine(assembleNative.get().outputs.files.singleFile, "--version") }
|
|
|
|
doLast {
|
|
val outputText = execOutput.standardOutput.asText.get()
|
|
if (!outputText.contains(buildInfo.pklVersionNonUnique)) {
|
|
throw GradleException(
|
|
"Expected version output to contain current version (${buildInfo.pklVersionNonUnique}), but got '$outputText'"
|
|
)
|
|
}
|
|
outputFile.get().asFile.toPath().apply {
|
|
try {
|
|
parent.createDirectories()
|
|
} catch (ignored: java.nio.file.FileAlreadyExistsException) {}
|
|
writeText("OK")
|
|
}
|
|
}
|
|
}
|
|
|
|
val requiredGlibcVersion: Version = Version.parse("2.17")
|
|
|
|
val checkGlibc by
|
|
tasks.registering {
|
|
enabled = buildInfo.os.isLinux && !buildInfo.musl
|
|
dependsOn(assembleNative)
|
|
doLast {
|
|
val exec =
|
|
providers.exec {
|
|
commandLine("objdump", "-T", assembleNative.get().outputs.files.singleFile)
|
|
}
|
|
val output = exec.standardOutput.asText.get()
|
|
val minimumGlibcVersion =
|
|
output
|
|
.split("\n")
|
|
.mapNotNull { line ->
|
|
val match = Regex("GLIBC_([.0-9]*)").find(line)
|
|
match?.groups[1]?.let { Version.parse(it.value) }
|
|
}
|
|
.maxOrNull()
|
|
if (minimumGlibcVersion == null) {
|
|
throw GradleException(
|
|
"Could not determine glibc version from executable. objdump output: $output"
|
|
)
|
|
}
|
|
if (minimumGlibcVersion > requiredGlibcVersion) {
|
|
throw GradleException(
|
|
"Incorrect glibc version. Found: $minimumGlibcVersion, required: $requiredGlibcVersion"
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Expose underlying task's outputs
|
|
private fun <T : Task> Task.wraps(other: TaskProvider<T>) {
|
|
dependsOn(other)
|
|
outputs.files(other)
|
|
}
|
|
|
|
val testNative by tasks.existing { dependsOn(testStartNativeExecutable, checkGlibc) }
|
|
|
|
val assembleNativeMacOsAarch64 by tasks.existing { wraps(macExecutableAarch64) }
|
|
|
|
val assembleNativeMacOsAmd64 by tasks.existing { wraps(macExecutableAmd64) }
|
|
|
|
val assembleNativeLinuxAarch64 by tasks.existing { wraps(linuxExecutableAarch64) }
|
|
|
|
val assembleNativeLinuxAmd64 by tasks.existing { wraps(linuxExecutableAmd64) }
|
|
|
|
val assembleNativeAlpineLinuxAmd64 by tasks.existing { wraps(alpineExecutableAmd64) }
|
|
|
|
val assembleNativeWindowsAmd64 by tasks.existing { wraps(windowsExecutableAmd64) }
|
|
|
|
publishing {
|
|
publications {
|
|
// need to put in `afterEvaluate` because `artifactId` cannot be set lazily.
|
|
project.afterEvaluate {
|
|
create<MavenPublication>("macExecutableAmd64") {
|
|
artifactId = "${executableSpec.publicationName.get()}-macos-amd64"
|
|
artifact(stagedMacAmd64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedMacAmd64Executable)
|
|
}
|
|
pom {
|
|
name = "${executableSpec.publicationName.get()}-macos-amd64"
|
|
url = executableSpec.website
|
|
description =
|
|
executableSpec.documentationName.map { name ->
|
|
"Native $name executable for macOS/amd64."
|
|
}
|
|
}
|
|
}
|
|
|
|
create<MavenPublication>("macExecutableAarch64") {
|
|
artifactId = "${executableSpec.publicationName.get()}-macos-aarch64"
|
|
artifact(stagedMacAarch64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedMacAarch64Executable)
|
|
}
|
|
pom {
|
|
name = "${executableSpec.publicationName.get()}-macos-aarch64"
|
|
url = executableSpec.website
|
|
description =
|
|
executableSpec.documentationName.map { name ->
|
|
"Native $name executable for macOS/aarch64."
|
|
}
|
|
}
|
|
}
|
|
|
|
create<MavenPublication>("linuxExecutableAmd64") {
|
|
artifactId = "${executableSpec.publicationName.get()}-linux-amd64"
|
|
artifact(stagedLinuxAmd64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedLinuxAmd64Executable)
|
|
}
|
|
pom {
|
|
name = "${executableSpec.publicationName.get()}-linux-amd64"
|
|
url = executableSpec.website
|
|
description =
|
|
executableSpec.documentationName.map { name ->
|
|
"Native $name executable for linux/amd64."
|
|
}
|
|
}
|
|
}
|
|
|
|
create<MavenPublication>("linuxExecutableAarch64") {
|
|
artifactId = "${executableSpec.publicationName.get()}-linux-aarch64"
|
|
artifact(stagedLinuxAarch64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedLinuxAarch64Executable)
|
|
}
|
|
pom {
|
|
name = "${executableSpec.publicationName.get()}-linux-aarch64"
|
|
url = executableSpec.website
|
|
description =
|
|
executableSpec.documentationName.map { name ->
|
|
"Native $name executable for linux/aarch64."
|
|
}
|
|
}
|
|
}
|
|
|
|
create<MavenPublication>("alpineLinuxExecutableAmd64") {
|
|
artifactId = "${executableSpec.publicationName.get()}-alpine-linux-amd64"
|
|
artifact(stagedAlpineLinuxAmd64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedAlpineLinuxAmd64Executable)
|
|
}
|
|
pom {
|
|
name = "${executableSpec.publicationName.get()}-alpine-linux-amd64"
|
|
url = executableSpec.website
|
|
description =
|
|
executableSpec.documentationName.map { name ->
|
|
"Native $name executable for linux/amd64 and statically linked to musl."
|
|
}
|
|
}
|
|
}
|
|
|
|
create<MavenPublication>("windowsExecutableAmd64") {
|
|
artifactId = "${executableSpec.publicationName.get()}-windows-amd64"
|
|
artifact(stagedWindowsAmd64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "exe"
|
|
builtBy(stagedWindowsAmd64Executable)
|
|
}
|
|
pom {
|
|
name = "${executableSpec.publicationName.get()}-windows-amd64"
|
|
url = executableSpec.website
|
|
description =
|
|
executableSpec.documentationName.map { name ->
|
|
"Native $name executable for windows/amd64."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
signing {
|
|
project.afterEvaluate {
|
|
sign(publishing.publications["linuxExecutableAarch64"])
|
|
sign(publishing.publications["linuxExecutableAmd64"])
|
|
sign(publishing.publications["macExecutableAarch64"])
|
|
sign(publishing.publications["macExecutableAmd64"])
|
|
sign(publishing.publications["alpineLinuxExecutableAmd64"])
|
|
sign(publishing.publications["windowsExecutableAmd64"])
|
|
}
|
|
}
|