Gradle: Replace legacy buildSrc mechanism with included build (#1524)

Motivation:
buildSrc is a special-case legacy mechanism.
Gradle recommends using an included build named build-logic instead:

https://docs.gradle.org/current/userguide/best_practices_structuring_builds.html#favor_composite_builds

Changes:
- Rename buildSrc/ to build-logic/
  - triggers reformatting
- Replace occurrences of "buildSrc" with "build-logic"
- Include the build-logic build in the main build (via
settings.gradle.kts)
- Apply convention plugins via plugin IDs instead of type-safe accessors
  - small tradeoff compared to buildSrc

Result:
- Faster and more isolated builds
- Build logic behaves like a normal build, making it easier to evolve
and reason about

---------

Co-authored-by: Daniel Chao <dan.chao@apple.com>
This commit is contained in:
odenix
2026-04-16 05:37:10 +01:00
committed by GitHub
parent 04a9cc90d2
commit 4faf35a66a
56 changed files with 343 additions and 350 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklJavaLibrary id("pklJavaLibrary")
id("me.champeau.jmh") id("me.champeau.jmh")
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -15,7 +15,7 @@
*/ */
@file:Suppress("UnstableApiUsage") @file:Suppress("UnstableApiUsage")
rootProject.name = "buildSrc" rootProject.name = "build-logic"
pluginManagement { pluginManagement {
repositories { repositories {
@@ -24,7 +24,7 @@ pluginManagement {
} }
} }
plugins { id("org.gradle.toolchains.foojay-resolver-convention") } plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" }
// makes ~/.gradle/init.gradle unnecessary and ~/.gradle/gradle.properties optional // makes ~/.gradle/init.gradle unnecessary and ~/.gradle/gradle.properties optional
dependencyResolutionManagement { dependencyResolutionManagement {
@@ -44,7 +44,7 @@ const val PKL_JVM_TARGET_DEFAULT_MAXIMUM = 17
* *
* This is a build-time requirement, not a runtime requirement. To avoid the provisioning of * This is a build-time requirement, not a runtime requirement. To avoid the provisioning of
* multiple JDKs and other build issues, keep this value in sync with the JVM toolchain versions in * multiple JDKs and other build issues, keep this value in sync with the JVM toolchain versions in
* `buildSrc/build.gradle.kts` and `gradle-daemon-jvm.properties`. * `build-logic/build.gradle.kts` and `gradle-daemon-jvm.properties`.
*/ */
const val PKL_JDK_VERSION_MIN = 25 const val PKL_JDK_VERSION_MIN = 25
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2025-2026 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.
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -55,13 +55,12 @@ abstract class NativeImageBuild : DefaultTask() {
@get:Inject protected abstract val execOperations: ExecOperations @get:Inject protected abstract val execOperations: ExecOperations
private val graalVm: Provider<BuildInfo.GraalVm> = private val graalVm: Provider<BuildInfo.GraalVm> = arch.map { a ->
arch.map { a -> when (a) {
when (a) { Architecture.AMD64 -> buildInfo.graalVmAmd64
Architecture.AMD64 -> buildInfo.graalVmAmd64 Architecture.AARCH64 -> buildInfo.graalVmAarch64
Architecture.AARCH64 -> buildInfo.graalVmAarch64
}
} }
}
private val buildInfo: BuildInfo = project.extensions.getByType(BuildInfo::class.java) private val buildInfo: BuildInfo = project.extensions.getByType(BuildInfo::class.java)
@@ -151,10 +150,9 @@ abstract class NativeImageBuild : DefaultTask() {
} }
// native-image rejects non-existing class path entries -> filter // native-image rejects non-existing class path entries -> filter
add("--class-path") add("--class-path")
val pathInput = val pathInput = classpath.filter {
classpath.filter { it.exists() && !exclusions.any { exclude -> it.name.contains(exclude) }
it.exists() && !exclusions.any { exclude -> it.name.contains(exclude) } }
}
add(pathInput.asPath) add(pathInput.asPath)
// make sure dev machine stays responsive (15% slowdown on my laptop) // make sure dev machine stays responsive (15% slowdown on my laptop)
val processors = val processors =
@@ -63,59 +63,58 @@ fun Project.configurePklPomMetadata() {
/** Configures POM validation task to check for unresolved versions and snapshots in releases. */ /** Configures POM validation task to check for unresolved versions and snapshots in releases. */
fun Project.configurePomValidation() { fun Project.configurePomValidation() {
val validatePom by val validatePom by tasks.registering {
tasks.registering { if (tasks.findByName("generatePomFileForLibraryPublication") == null) {
if (tasks.findByName("generatePomFileForLibraryPublication") == null) { return@registering
return@registering }
} val generatePomFileForLibraryPublication by tasks.existing(GenerateMavenPom::class)
val generatePomFileForLibraryPublication by tasks.existing(GenerateMavenPom::class) val outputFile =
val outputFile = layout.buildDirectory.file("validatePom") // dummy output to satisfy up-to-date check
layout.buildDirectory.file("validatePom") // dummy output to satisfy up-to-date check
dependsOn(generatePomFileForLibraryPublication) dependsOn(generatePomFileForLibraryPublication)
inputs.file(generatePomFileForLibraryPublication.get().destination) inputs.file(generatePomFileForLibraryPublication.get().destination)
outputs.file(outputFile) outputs.file(outputFile)
doLast { doLast {
outputFile.get().asFile.delete() outputFile.get().asFile.delete()
val pomFile = generatePomFileForLibraryPublication.get().destination val pomFile = generatePomFileForLibraryPublication.get().destination
assert(pomFile.exists()) assert(pomFile.exists())
val text = pomFile.readText() val text = pomFile.readText()
run { run {
val unresolvedVersion = Regex("<version>.*[+,()\\[\\]].*</version>") val unresolvedVersion = Regex("<version>.*[+,()\\[\\]].*</version>")
val matches = unresolvedVersion.findAll(text).toList() val matches = unresolvedVersion.findAll(text).toList()
if (matches.isNotEmpty()) { if (matches.isNotEmpty()) {
throw org.gradle.api.GradleException( throw org.gradle.api.GradleException(
""" """
Found unresolved version selector(s) in generated POM: Found unresolved version selector(s) in generated POM:
${matches.joinToString("\n") { it.groupValues[0] }} ${matches.joinToString("\n") { it.groupValues[0] }}
""" """
.trimIndent() .trimIndent()
) )
}
} }
}
val buildInfo = project.extensions.getByType<BuildInfo>() val buildInfo = project.extensions.getByType<BuildInfo>()
if (buildInfo.isReleaseBuild) { if (buildInfo.isReleaseBuild) {
val snapshotVersion = Regex("<version>.*-SNAPSHOT</version>") val snapshotVersion = Regex("<version>.*-SNAPSHOT</version>")
val matches = snapshotVersion.findAll(text).toList() val matches = snapshotVersion.findAll(text).toList()
if (matches.isNotEmpty()) { if (matches.isNotEmpty()) {
throw org.gradle.api.GradleException( throw org.gradle.api.GradleException(
""" """
Found snapshot version(s) in generated POM of Pkl release version: Found snapshot version(s) in generated POM of Pkl release version:
${matches.joinToString("\n") { it.groupValues[0] }} ${matches.joinToString("\n") { it.groupValues[0] }}
""" """
.trimIndent() .trimIndent()
) )
}
} }
outputFile.get().asFile.writeText("OK")
} }
outputFile.get().asFile.writeText("OK")
} }
}
tasks.named("publish") { dependsOn(validatePom) } tasks.named("publish") { dependsOn(validatePom) }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -112,7 +112,7 @@ tasks.withType(JavaExec::class).configureEach {
private val libs = the<LibrariesForLibs>() private val libs = the<LibrariesForLibs>()
private val licenseHeaderFile by lazy { private val licenseHeaderFile by lazy {
rootProject.file("buildSrc/src/main/resources/license-header.star-block.txt") rootProject.file("build-logic/src/main/resources/license-header.star-block.txt")
} }
private fun KotlinGradleExtension.configureFormatter() { private fun KotlinGradleExtension.configureFormatter() {
@@ -136,18 +136,18 @@ spotless {
val revertYearOnlyChangesStep = val revertYearOnlyChangesStep =
RevertYearOnlyChangesStep(rootProject.rootDir, ratchetFrom!!).create() RevertYearOnlyChangesStep(rootProject.rootDir, ratchetFrom!!).create()
// When building root project, format buildSrc files too. // When building root project, format build-logic files too.
// We need this because buildSrc is not a subproject of the root project, so a top-level // We need this because build-logic is not a subproject of the root project, so a top-level
// `spotlessApply` will not trigger `buildSrc:spotlessApply`. // `spotlessApply` will not trigger `build-logic:spotlessApply`.
if (project === rootProject) { if (project.path == rootProject.path) {
kotlinGradle { kotlinGradle {
configureFormatter() configureFormatter()
addStep(revertYearOnlyChangesStep) addStep(revertYearOnlyChangesStep)
target("*.kts", "buildSrc/*.kts", "buildSrc/src/*/kotlin/**/*.kts") target("*.kts", "build-logic/*.kts", "build-logic/src/*/kotlin/**/*.kts")
} }
kotlin { kotlin {
ktfmt(libs.versions.ktfmt.get()).googleStyle() ktfmt(libs.versions.ktfmt.get()).googleStyle()
target("buildSrc/src/*/kotlin/**/*.kt") target("build-logic/src/*/kotlin/**/*.kt")
licenseHeaderFile(licenseHeaderFile) licenseHeaderFile(licenseHeaderFile)
addStep(revertYearOnlyChangesStep) addStep(revertYearOnlyChangesStep)
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -47,20 +47,19 @@ fun Task.setupTestStartJavaExecutable(launcher: Provider<JavaLauncher>? = null)
val outputFile = layout.buildDirectory.file("testStartJavaExecutable/$name") val outputFile = layout.buildDirectory.file("testStartJavaExecutable/$name")
outputs.file(outputFile) outputs.file(outputFile)
val execOutput = val execOutput = providers.exec {
providers.exec { val executablePath = javaExecutable.get().outputs.files.singleFile
val executablePath = javaExecutable.get().outputs.files.singleFile if (launcher?.isPresent == true) {
if (launcher?.isPresent == true) { commandLine(
commandLine( launcher.get().executablePath.asFile.absolutePath,
launcher.get().executablePath.asFile.absolutePath, "-jar",
"-jar", executablePath.absolutePath,
executablePath.absolutePath, "--version",
"--version", )
) } else {
} else { commandLine(executablePath.absolutePath, "--version")
commandLine(executablePath.absolutePath, "--version")
}
} }
}
doLast { doLast {
val outputText = execOutput.standardOutput.asText.get() val outputText = execOutput.standardOutput.asText.get()
@@ -56,7 +56,9 @@ spotless {
addStep(revertYearOnlyChanges) addStep(revertYearOnlyChanges)
googleJavaFormat(libs.versions.googleJavaFormat.get()) googleJavaFormat(libs.versions.googleJavaFormat.get())
target("src/*/java/**/*.java") target("src/*/java/**/*.java")
licenseHeaderFile(rootProject.file("buildSrc/src/main/resources/license-header.star-block.txt")) licenseHeaderFile(
rootProject.file("build-logic/src/main/resources/license-header.star-block.txt")
)
} }
} }
@@ -56,7 +56,9 @@ spotless {
addStep(revertYearOnlyChanges) addStep(revertYearOnlyChanges)
ktfmt(libs.versions.ktfmt.get()).googleStyle() ktfmt(libs.versions.ktfmt.get()).googleStyle()
target("src/*/kotlin/**/*.kt") target("src/*/kotlin/**/*.kt")
licenseHeaderFile(rootProject.file("buildSrc/src/main/resources/license-header.star-block.txt")) licenseHeaderFile(
rootProject.file("build-logic/src/main/resources/license-header.star-block.txt")
)
} }
} }
@@ -37,16 +37,15 @@ val stagedLinuxAarch64Executable: Configuration by configurations.creating
val stagedAlpineLinuxAmd64Executable: Configuration by configurations.creating val stagedAlpineLinuxAmd64Executable: Configuration by configurations.creating
val stagedWindowsAmd64Executable: Configuration by configurations.creating val stagedWindowsAmd64Executable: Configuration by configurations.creating
val nativeImageClasspath by val nativeImageClasspath by configurations.creating {
configurations.creating { extendsFrom(configurations.runtimeClasspath.get())
extendsFrom(configurations.runtimeClasspath.get()) // Ensure native-image version uses GraalVM C SDKs instead of Java FFI or JNA
// Ensure native-image version uses GraalVM C SDKs instead of Java FFI or JNA // (comes from artifact `mordant-jvm-graal-ffi`).
// (comes from artifact `mordant-jvm-graal-ffi`). exclude("com.github.ajalt.mordant", "mordant-jvm-ffm")
exclude("com.github.ajalt.mordant", "mordant-jvm-ffm") exclude("com.github.ajalt.mordant", "mordant-jvm-ffm-jvm")
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") exclude("com.github.ajalt.mordant", "mordant-jvm-jna-jvm")
exclude("com.github.ajalt.mordant", "mordant-jvm-jna-jvm") }
}
val libs = the<LibrariesForLibs>() val libs = the<LibrariesForLibs>()
@@ -140,65 +139,63 @@ val windowsExecutableAmd64 by
val assembleNative by tasks.existing val assembleNative by tasks.existing
val testStartNativeExecutable by val testStartNativeExecutable by tasks.registering {
tasks.registering { dependsOn(assembleNative)
dependsOn(assembleNative)
// dummy file for up-to-date checking // dummy file for up-to-date checking
val outputFile = project.layout.buildDirectory.file("testStartNativeExecutable/output.txt") val outputFile = project.layout.buildDirectory.file("testStartNativeExecutable/output.txt")
outputs.file(outputFile) outputs.file(outputFile)
val execOutput = val execOutput = providers.exec {
providers.exec { commandLine(assembleNative.get().outputs.files.singleFile, "--version") } commandLine(assembleNative.get().outputs.files.singleFile, "--version")
}
doLast { doLast {
val outputText = execOutput.standardOutput.asText.get() val outputText = execOutput.standardOutput.asText.get()
if (!outputText.contains(buildInfo.pklVersionNonUnique)) { if (!outputText.contains(buildInfo.pklVersionNonUnique)) {
throw GradleException( throw GradleException(
"Expected version output to contain current version (${buildInfo.pklVersionNonUnique}), but got '$outputText'" "Expected version output to contain current version (${buildInfo.pklVersionNonUnique}), but got '$outputText'"
) )
} }
outputFile.get().asFile.toPath().apply { outputFile.get().asFile.toPath().apply {
try { try {
parent.createDirectories() parent.createDirectories()
} catch (_: java.nio.file.FileAlreadyExistsException) {} } catch (_: java.nio.file.FileAlreadyExistsException) {}
writeText("OK") writeText("OK")
}
} }
} }
}
val requiredGlibcVersion: Version = Version.parse("2.17") val requiredGlibcVersion: Version = Version.parse("2.17")
val checkGlibc by val checkGlibc by tasks.registering {
tasks.registering { enabled = buildInfo.os.isLinux && !buildInfo.musl
enabled = buildInfo.os.isLinux && !buildInfo.musl dependsOn(assembleNative)
dependsOn(assembleNative) doLast {
doLast { val exec = providers.exec {
val exec = commandLine("objdump", "-T", assembleNative.get().outputs.files.singleFile)
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) }
} }
val output = exec.standardOutput.asText.get() .maxOrNull()
val minimumGlibcVersion = if (minimumGlibcVersion == null) {
output throw GradleException(
.split("\n") "Could not determine glibc version from executable. objdump output: $output"
.mapNotNull { line -> )
val match = Regex("GLIBC_([.0-9]*)").find(line) }
match?.groups[1]?.let { Version.parse(it.value) } if (minimumGlibcVersion > requiredGlibcVersion) {
} throw GradleException(
.maxOrNull() "Incorrect glibc version. Found: $minimumGlibcVersion, required: $requiredGlibcVersion"
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 // Expose underlying task's outputs
private fun <T : Task> Task.wraps(other: TaskProvider<T>) { private fun <T : Task> Task.wraps(other: TaskProvider<T>) {
@@ -0,0 +1,122 @@
/*
* Copyright © 2024-2026 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.
*/
val assembleNativeMacOsAarch64 by tasks.registering { group = "build" }
val assembleNativeMacOsAmd64 by tasks.registering { group = "build" }
val assembleNativeLinuxAarch64 by tasks.registering { group = "build" }
val assembleNativeLinuxAmd64 by tasks.registering { group = "build" }
val assembleNativeAlpineLinuxAmd64 by tasks.registering { group = "build" }
val assembleNativeWindowsAmd64 by tasks.registering { group = "build" }
val testNativeMacOsAarch64 by tasks.registering { group = "verification" }
val testNativeMacOsAmd64 by tasks.registering { group = "verification" }
val testNativeLinuxAarch64 by tasks.registering { group = "verification" }
val testNativeLinuxAmd64 by tasks.registering { group = "verification" }
val testNativeAlpineLinuxAmd64 by tasks.registering { group = "verification" }
val testNativeWindowsAmd64 by tasks.registering { group = "verification" }
val buildInfo = project.extensions.getByType<BuildInfo>()
private fun <T : Task> Task.wraps(other: TaskProvider<T>) {
dependsOn(other)
outputs.files(other)
}
val assembleNative by tasks.registering {
group = "build"
if (!buildInfo.isCrossArchSupported && buildInfo.isCrossArch) {
throw GradleException("Cross-arch builds are not supported on ${buildInfo.os.name}")
}
when {
buildInfo.os.isMacOsX && buildInfo.targetArch == "aarch64" -> {
wraps(assembleNativeMacOsAarch64)
}
buildInfo.os.isMacOsX && buildInfo.targetArch == "amd64" -> {
wraps(assembleNativeMacOsAmd64)
}
buildInfo.os.isLinux && buildInfo.targetArch == "aarch64" -> {
wraps(assembleNativeLinuxAarch64)
}
buildInfo.os.isLinux && buildInfo.targetArch == "amd64" -> {
if (buildInfo.musl) wraps(assembleNativeAlpineLinuxAmd64) else wraps(assembleNativeLinuxAmd64)
}
buildInfo.os.isWindows && buildInfo.targetArch == "amd64" -> {
wraps(assembleNativeWindowsAmd64)
}
else -> {
doLast {
throw GradleException(
"Cannot build targeting ${buildInfo.os.name}/${buildInfo.targetArch} with musl=${buildInfo.musl}"
)
}
}
}
}
val testNative by tasks.registering {
group = "verification"
dependsOn(assembleNative)
if (!buildInfo.isCrossArchSupported && buildInfo.isCrossArch) {
throw GradleException("Cross-arch builds are not supported on ${buildInfo.os.name}")
}
when {
buildInfo.os.isMacOsX && buildInfo.targetArch == "aarch64" -> {
dependsOn(testNativeMacOsAarch64)
}
buildInfo.os.isMacOsX && buildInfo.targetArch == "amd64" -> {
dependsOn(testNativeMacOsAmd64)
}
buildInfo.os.isLinux && buildInfo.targetArch == "aarch64" -> {
dependsOn(testNativeLinuxAarch64)
}
buildInfo.os.isLinux && buildInfo.targetArch == "amd64" -> {
if (buildInfo.musl) dependsOn(testNativeAlpineLinuxAmd64) else dependsOn(testNativeLinuxAmd64)
}
buildInfo.os.isWindows && buildInfo.targetArch == "amd64" -> {
dependsOn(testNativeWindowsAmd64)
}
else -> {
doLast {
throw GradleException(
"Cannot build targeting ${buildInfo.os.name}/${buildInfo.targetArch} with musl=${buildInfo.musl}"
)
}
}
}
}
val checkNative by tasks.registering {
group = "verification"
dependsOn(testNative)
}
val buildNative by tasks.registering {
group = "build"
dependsOn(checkNative)
}
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2025-2026 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.
@@ -24,7 +24,7 @@ spotless {
target("**/*.pkl") target("**/*.pkl")
addStep(PklFormatterStep(pklFormatter).create()) addStep(PklFormatterStep(pklFormatter).create())
licenseHeaderFile( licenseHeaderFile(
rootProject.file("buildSrc/src/main/resources/license-header.line-comment.txt"), rootProject.file("build-logic/src/main/resources/license-header.line-comment.txt"),
"/// ", "/// ",
) )
// disable ratcheting for Pkl sources // disable ratcheting for Pkl sources
+2 -2
View File
@@ -19,8 +19,8 @@ import org.jetbrains.gradle.ext.ActionDelegationConfig.TestRunner.PLATFORM
import org.jetbrains.gradle.ext.ProjectSettings import org.jetbrains.gradle.ext.ProjectSettings
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklGraalVm id("pklGraalVm")
alias(libs.plugins.ideaExt) alias(libs.plugins.ideaExt)
alias(libs.plugins.jmh) apply false alias(libs.plugins.jmh) apply false
@@ -1,128 +0,0 @@
/*
* 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.
* 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.
*/
val assembleNativeMacOsAarch64 by tasks.registering { group = "build" }
val assembleNativeMacOsAmd64 by tasks.registering { group = "build" }
val assembleNativeLinuxAarch64 by tasks.registering { group = "build" }
val assembleNativeLinuxAmd64 by tasks.registering { group = "build" }
val assembleNativeAlpineLinuxAmd64 by tasks.registering { group = "build" }
val assembleNativeWindowsAmd64 by tasks.registering { group = "build" }
val testNativeMacOsAarch64 by tasks.registering { group = "verification" }
val testNativeMacOsAmd64 by tasks.registering { group = "verification" }
val testNativeLinuxAarch64 by tasks.registering { group = "verification" }
val testNativeLinuxAmd64 by tasks.registering { group = "verification" }
val testNativeAlpineLinuxAmd64 by tasks.registering { group = "verification" }
val testNativeWindowsAmd64 by tasks.registering { group = "verification" }
val buildInfo = project.extensions.getByType<BuildInfo>()
private fun <T : Task> Task.wraps(other: TaskProvider<T>) {
dependsOn(other)
outputs.files(other)
}
val assembleNative by
tasks.registering {
group = "build"
if (!buildInfo.isCrossArchSupported && buildInfo.isCrossArch) {
throw GradleException("Cross-arch builds are not supported on ${buildInfo.os.name}")
}
when {
buildInfo.os.isMacOsX && buildInfo.targetArch == "aarch64" -> {
wraps(assembleNativeMacOsAarch64)
}
buildInfo.os.isMacOsX && buildInfo.targetArch == "amd64" -> {
wraps(assembleNativeMacOsAmd64)
}
buildInfo.os.isLinux && buildInfo.targetArch == "aarch64" -> {
wraps(assembleNativeLinuxAarch64)
}
buildInfo.os.isLinux && buildInfo.targetArch == "amd64" -> {
if (buildInfo.musl) wraps(assembleNativeAlpineLinuxAmd64)
else wraps(assembleNativeLinuxAmd64)
}
buildInfo.os.isWindows && buildInfo.targetArch == "amd64" -> {
wraps(assembleNativeWindowsAmd64)
}
else -> {
doLast {
throw GradleException(
"Cannot build targeting ${buildInfo.os.name}/${buildInfo.targetArch} with musl=${buildInfo.musl}"
)
}
}
}
}
val testNative by
tasks.registering {
group = "verification"
dependsOn(assembleNative)
if (!buildInfo.isCrossArchSupported && buildInfo.isCrossArch) {
throw GradleException("Cross-arch builds are not supported on ${buildInfo.os.name}")
}
when {
buildInfo.os.isMacOsX && buildInfo.targetArch == "aarch64" -> {
dependsOn(testNativeMacOsAarch64)
}
buildInfo.os.isMacOsX && buildInfo.targetArch == "amd64" -> {
dependsOn(testNativeMacOsAmd64)
}
buildInfo.os.isLinux && buildInfo.targetArch == "aarch64" -> {
dependsOn(testNativeLinuxAarch64)
}
buildInfo.os.isLinux && buildInfo.targetArch == "amd64" -> {
if (buildInfo.musl) dependsOn(testNativeAlpineLinuxAmd64)
else dependsOn(testNativeLinuxAmd64)
}
buildInfo.os.isWindows && buildInfo.targetArch == "amd64" -> {
dependsOn(testNativeWindowsAmd64)
}
else -> {
doLast {
throw GradleException(
"Cannot build targeting ${buildInfo.os.name}/${buildInfo.targetArch} with musl=${buildInfo.musl}"
)
}
}
}
}
val checkNative by
tasks.registering {
group = "verification"
dependsOn(testNative)
}
val buildNative by
tasks.registering {
group = "build"
dependsOn(checkNative)
}
+3 -3
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -16,8 +16,8 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinTest id("pklKotlinTest")
} }
sourceSets { sourceSets {
+1 -1
View File
@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
`java-platform` `java-platform`
`maven-publish` `maven-publish`
signing signing
+6 -6
View File
@@ -18,14 +18,14 @@ import java.io.OutputStream
import org.gradle.kotlin.dsl.support.serviceOf import org.gradle.kotlin.dsl.support.serviceOf
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinLibrary id("pklKotlinLibrary")
pklPublishLibrary id("pklPublishLibrary")
pklJavaExecutable id("pklJavaExecutable")
pklNativeExecutable id("pklNativeExecutable")
`maven-publish` `maven-publish`
// already on build script class path (see buildSrc/build.gradle.kts), // already on build script class path (see build-logic/build.gradle.kts),
// hence must only specify plugin ID here // hence must only specify plugin ID here
id(libs.plugins.shadow.get().pluginId) id(libs.plugins.shadow.get().pluginId)
+6 -6
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinLibrary id("pklKotlinLibrary")
pklPublishLibrary id("pklPublishLibrary")
pklJavaExecutable id("pklJavaExecutable")
} }
dependencies { dependencies {
@@ -56,7 +56,7 @@ publishing {
""" """
Java source code generator that generates corresponding Java classes for Pkl classes, Java source code generator that generates corresponding Java classes for Pkl classes,
simplifying consumption of Pkl configuration as statically typed Java objects. simplifying consumption of Pkl configuration as statically typed Java objects.
""" """
.trimIndent() .trimIndent()
) )
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinLibrary id("pklKotlinLibrary")
pklPublishLibrary id("pklPublishLibrary")
pklJavaExecutable id("pklJavaExecutable")
} }
publishing { publishing {
@@ -29,7 +29,7 @@ publishing {
""" """
Kotlin source code generator that generates corresponding Kotlin classes for Pkl classes, Kotlin source code generator that generates corresponding Kotlin classes for Pkl classes,
simplifying consumption of Pkl configuration as statically typed Kotlin objects. simplifying consumption of Pkl configuration as statically typed Kotlin objects.
""" """
.trimIndent() .trimIndent()
) )
} }
+4 -4
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinLibrary id("pklKotlinLibrary")
pklPublishLibrary id("pklPublishLibrary")
} }
val svmClasspath: Configuration by configurations.creating val svmClasspath: Configuration by configurations.creating
+3 -3
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -16,8 +16,8 @@
import java.security.MessageDigest import java.security.MessageDigest
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinLibrary id("pklKotlinLibrary")
} }
// note: no need to publish this library // note: no need to publish this library
+4 -4
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinLibrary id("pklKotlinLibrary")
pklPublishLibrary id("pklPublishLibrary")
} }
publishing { publishing {
+5 -5
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklJavaLibrary id("pklJavaLibrary")
pklFatJar id("pklFatJar")
pklPublishLibrary id("pklPublishLibrary")
signing signing
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinLibrary id("pklKotlinLibrary")
pklPublishLibrary id("pklPublishLibrary")
} }
val pklConfigJava: Configuration by configurations.creating val pklConfigJava: Configuration by configurations.creating
+4 -4
View File
@@ -17,10 +17,10 @@ import org.apache.tools.ant.filters.ReplaceTokens
plugins { plugins {
kotlin("jvm") // for `src/generator/kotlin` kotlin("jvm") // for `src/generator/kotlin`
pklAllProjects id("pklAllProjects")
pklJavaLibrary id("pklJavaLibrary")
pklPublishLibrary id("pklPublishLibrary")
pklNativeLifecycle id("pklNativeLifecycle")
idea idea
} }
+6 -6
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,11 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinLibrary id("pklKotlinLibrary")
pklJavaExecutable id("pklJavaExecutable")
pklNativeExecutable id("pklNativeExecutable")
pklHtmlValidator id("pklHtmlValidator")
alias(libs.plugins.kotlinxSerialization) alias(libs.plugins.kotlinxSerialization)
} }
+3 -3
View File
@@ -17,9 +17,9 @@ import java.nio.file.Files
import java.nio.file.LinkOption import java.nio.file.LinkOption
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklJavaLibrary id("pklJavaLibrary")
pklPublishLibrary id("pklPublishLibrary")
} }
val pklDistributionCurrent: Configuration by configurations.creating val pklDistributionCurrent: Configuration by configurations.creating
+3 -3
View File
@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklJavaLibrary id("pklJavaLibrary")
pklPublishLibrary id("pklPublishLibrary")
} }
dependencies { dependencies {
+5 -5
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklJavaLibrary id("pklJavaLibrary")
pklGradlePluginTest id("pklGradlePluginTest")
`java-gradle-plugin` `java-gradle-plugin`
`maven-publish` `maven-publish`
pklPublishLibrary id("pklPublishLibrary")
signing signing
} }
+4 -4
View File
@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklJavaLibrary id("pklJavaLibrary")
pklJSpecify id("pklJSpecify")
pklPublishLibrary id("pklPublishLibrary")
idea idea
} }
+3 -3
View File
@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklKotlinLibrary id("pklKotlinLibrary")
pklNativeLifecycle id("pklNativeLifecycle")
} }
dependencies { dependencies {
+3 -3
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -20,8 +20,8 @@ import kotlin.io.path.createDirectories
import kotlin.io.path.writeText import kotlin.io.path.writeText
plugins { plugins {
pklAllProjects id("pklAllProjects")
pklFatJar id("pklFatJar")
signing signing
} }
+2
View File
@@ -15,6 +15,8 @@
*/ */
rootProject.name = "pkl" rootProject.name = "pkl"
includeBuild("build-logic")
include("bench") include("bench")
include("docs") include("docs")
+4 -4
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 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.
@@ -14,11 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
pklAllProjects id("pklAllProjects")
base base
`maven-publish` `maven-publish`
pklPublishLibrary id("pklPublishLibrary")
pklSpotlessFormat id("pklSpotlessFormat")
signing signing
} }