mirror of
https://github.com/apple/pkl.git
synced 2026-08-26 21:54:03 +02:00
Introduce C library for Pkl (#1238)
This uses native-image to generate a C library for Pkl. This generated library from native-image is wrapped with our own library, in `pkl.h`. This produces a static and a dynamic library for each os/arch variant that Pkl currently supports. Co-authored-by: Kushal Pisavadia <kushal.p@apple.com> Co-authored-by: Jen Basch <jbasch94@gmail.com> Co-authored-by: Islon Scherer <i_desouzascherer@apple.com>
This commit is contained in:
co-authored by
Kushal Pisavadia
Jen Basch
Islon Scherer
parent
175e2b6273
commit
67df676359
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
import Target.Arch
|
||||
import Target.OS
|
||||
import java.io.File
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.VersionCatalog
|
||||
import org.gradle.api.artifacts.VersionCatalogsExtension
|
||||
@@ -102,29 +105,31 @@ open class BuildInfo(private val project: Project) {
|
||||
val installDir: File by lazy { File(homeDir, baseName) }
|
||||
|
||||
val baseDir: String by lazy {
|
||||
if (os.isMacOsX) "$installDir/Contents/Home" else installDir.toString()
|
||||
if (os.isMacOS) "$installDir/Contents/Home" else installDir.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/** The target machine to build, defaulting to the host system machine. */
|
||||
val targetMachine: Target by lazy { Target.from(os = os, arch = targetArch, musl = musl) }
|
||||
|
||||
/** The target architecture to build, defaulting to the system architecture. */
|
||||
val targetArch by lazy { System.getProperty("pkl.targetArch") ?: arch }
|
||||
val targetArch: Arch by lazy { System.getProperty("pkl.targetArch")?.let(Arch::fromName) ?: arch }
|
||||
|
||||
/** Tells if this is a cross-arch build (e.g. targeting amd64 when on an aarch64 machine). */
|
||||
val isCrossArch by lazy { arch != targetArch }
|
||||
|
||||
/** Tells if cross-arch builds are supported on this machine. */
|
||||
val isCrossArchSupported by lazy { os.isMacOsX }
|
||||
val isCrossArchSupported by lazy { os.isMacOS }
|
||||
|
||||
/** Whether to build native executables using the musl toolchain or not. */
|
||||
val musl: Boolean by lazy { java.lang.Boolean.getBoolean("pkl.musl") }
|
||||
|
||||
/** Same logic as [org.gradle.internal.os.OperatingSystem#arch], which is protected. */
|
||||
val arch: String by lazy {
|
||||
val arch: Arch by lazy {
|
||||
when (val arch = System.getProperty("os.arch")) {
|
||||
"x86" -> "i386"
|
||||
"x86_64" -> "amd64"
|
||||
"powerpc" -> "ppc"
|
||||
else -> arch
|
||||
"x86_64",
|
||||
"amd64" -> Arch.AMD64
|
||||
"aarch64" -> Arch.AARCH64
|
||||
else -> throw GradleException("Cannot build Pkl on arch: $arch")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,10 +140,10 @@ open class BuildInfo(private val project: Project) {
|
||||
private fun createGraalVm(arch: String): GraalVm {
|
||||
val osName =
|
||||
when {
|
||||
os.isMacOsX -> "macos"
|
||||
os.isMacOS -> "macos"
|
||||
os.isLinux -> "linux"
|
||||
os.isWindows -> "windows"
|
||||
else -> throw RuntimeException("Unsupported OS for GraalVM: ${os.canonicalName}")
|
||||
else -> throw RuntimeException("Unsupported OS for GraalVM: ${os.name}")
|
||||
}
|
||||
val version = libs.findVersion("graalVm").get().toString()
|
||||
val graalJdkVersion = libs.findVersion("graalVmJdkVersion").get().toString()
|
||||
@@ -378,7 +383,15 @@ open class BuildInfo(private val project: Project) {
|
||||
File(System.getProperty("user.home"), "staticdeps/bin/x86_64-linux-musl-gcc").exists()
|
||||
}
|
||||
|
||||
val os: OperatingSystem by lazy { OperatingSystem.current() }
|
||||
val os: OS by lazy {
|
||||
val currentOs = OperatingSystem.current()
|
||||
when {
|
||||
currentOs.isMacOsX -> OS.MacOS
|
||||
currentOs.isLinux -> OS.Linux
|
||||
currentOs.isWindows -> OS.Windows
|
||||
else -> throw GradleException("Cannot build on ${currentOs.name}")
|
||||
}
|
||||
}
|
||||
|
||||
// could be `commitId: Provider<String> = project.provider { ... }`
|
||||
val commitId: String by lazy {
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright © 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.
|
||||
*/
|
||||
import Target.OS
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.process.ExecOperations
|
||||
|
||||
/**
|
||||
* Task for creating static libraries from object files.
|
||||
*
|
||||
* Supports both Unix `ar` and Windows `lib.exe`.
|
||||
*/
|
||||
abstract class CArchive : DefaultTask() {
|
||||
/** The object files to archive. */
|
||||
@get:InputFiles abstract val objectFiles: ConfigurableFileCollection
|
||||
|
||||
/** The output static library file. */
|
||||
@get:OutputFile abstract val outputFile: RegularFileProperty
|
||||
|
||||
@get:Inject protected abstract val execOperations: ExecOperations
|
||||
|
||||
private val buildInfo: BuildInfo = project.extensions.getByType(BuildInfo::class.java)
|
||||
|
||||
init {
|
||||
group = "build"
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun archive() {
|
||||
outputFile.get().asFile.delete()
|
||||
when (buildInfo.os) {
|
||||
OS.Linux,
|
||||
OS.MacOS -> archiveWithAr()
|
||||
OS.Windows -> archiveWithLib()
|
||||
}
|
||||
logger.info("Created static library -> ${outputFile.get().asFile.name}")
|
||||
}
|
||||
|
||||
private fun archiveWithAr() {
|
||||
val output = outputFile.get().asFile
|
||||
output.parentFile.mkdirs()
|
||||
|
||||
val args = buildList {
|
||||
add("ar")
|
||||
add("-rcs")
|
||||
add(output.absolutePath)
|
||||
objectFiles.files.forEach { file -> add(file.absolutePath) }
|
||||
}
|
||||
|
||||
execOperations.exec {
|
||||
workingDir = project.projectDir
|
||||
commandLine(args)
|
||||
}
|
||||
}
|
||||
|
||||
private fun archiveWithLib() {
|
||||
val output = outputFile.get().asFile
|
||||
output.parentFile.mkdirs()
|
||||
|
||||
val args = buildList {
|
||||
add("lib.exe")
|
||||
add("/OUT:${output.absolutePath}")
|
||||
objectFiles.files.forEach { file -> add(file.absolutePath) }
|
||||
}
|
||||
|
||||
execOperations.exec {
|
||||
workingDir = project.projectDir
|
||||
commandLine(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Copyright © 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.
|
||||
*/
|
||||
import Target.OS
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.process.ExecOperations
|
||||
|
||||
/**
|
||||
* Task for compiling C source files to object files or executables. Supports both GCC/Clang and
|
||||
* MSVC compilers.
|
||||
*/
|
||||
abstract class CCompile : DefaultTask() {
|
||||
/** The C source files to compile. */
|
||||
@get:InputFiles abstract val sourceFiles: ConfigurableFileCollection
|
||||
|
||||
/** The include directories for compilation. */
|
||||
@get:InputFiles abstract val includeDirs: ConfigurableFileCollection
|
||||
|
||||
/** Preprocessor definitions. */
|
||||
@get:Input @get:Optional abstract val defines: MapProperty<String, String>
|
||||
|
||||
/** C standard version (e.g., "c11", "c17", "gnu11"). */
|
||||
@get:Input @get:Optional abstract val cStandard: Property<String>
|
||||
|
||||
/** Optimization level (e.g., "0", "1", "2", "3", "s", "fast"). */
|
||||
@get:Input @get:Optional abstract val optimizationLevel: Property<String>
|
||||
|
||||
/** Whether to include debug symbols. */
|
||||
@get:Input abstract val debugSymbols: Property<Boolean>
|
||||
|
||||
/** Whether to generate position-independent code (GCC/Clang only). */
|
||||
@get:Input abstract val positionIndependentCode: Property<Boolean>
|
||||
|
||||
/** Warning flags (GCC/Clang: prefixed with -W, e.g., "all", "extra"). */
|
||||
@get:Input abstract val warningFlags: ListProperty<String>
|
||||
|
||||
/** Warning level for MSVC (0-4). */
|
||||
@get:Input @get:Optional abstract val warningLevel: Property<Int>
|
||||
|
||||
/** Feature flags (GCC/Clang only, prefixed with -f). */
|
||||
@get:Input abstract val featureFlags: ListProperty<String>
|
||||
|
||||
/** Machine-specific flags (GCC/Clang only, prefixed with -m). */
|
||||
@get:Input abstract val machineFlags: ListProperty<String>
|
||||
|
||||
/** Runtime library for MSVC (e.g., "MT", "MD", "MTd", "MDd"). */
|
||||
@get:Input @get:Optional abstract val runtimeLibrary: Property<String>
|
||||
|
||||
/** Additional compiler arguments. */
|
||||
@get:Input abstract val compilerArgs: ListProperty<String>
|
||||
|
||||
/** The architecture to compile for (macOS only). */
|
||||
@get:Input @get:Optional abstract val arch: Property<Target.Arch>
|
||||
|
||||
// ===== Linking properties =====
|
||||
|
||||
/** Whether to link into an executable (true) or just compile to object files (false). */
|
||||
@get:Input abstract val link: Property<Boolean>
|
||||
|
||||
/** Library search paths. */
|
||||
@get:InputFiles @get:Optional abstract val libraryPaths: ConfigurableFileCollection
|
||||
|
||||
/** Libraries to link by name. */
|
||||
@get:Input @get:Optional abstract val libraries: ListProperty<String>
|
||||
|
||||
/** Direct library files to link. */
|
||||
@get:InputFiles @get:Optional abstract val libraryFiles: ConfigurableFileCollection
|
||||
|
||||
/** Linker flags. */
|
||||
@get:Input @get:Optional abstract val linkerFlags: ListProperty<String>
|
||||
|
||||
/** macOS frameworks to link (GCC/Clang only). */
|
||||
@get:Input @get:Optional abstract val frameworks: ListProperty<String>
|
||||
|
||||
/** Output file when linking (executable name). */
|
||||
@get:OutputFile @get:Optional abstract val outputFile: RegularFileProperty
|
||||
|
||||
/** Create a shared library (dll, dylib, so). */
|
||||
@get:Input abstract val sharedLibrary: Property<Boolean>
|
||||
|
||||
/** The output directory for object files (when not linking). */
|
||||
@get:OutputDirectory @get:Optional abstract val outputDir: DirectoryProperty
|
||||
|
||||
@get:Inject protected abstract val execOperations: ExecOperations
|
||||
|
||||
private val buildInfo: BuildInfo = project.extensions.getByType(BuildInfo::class.java)
|
||||
|
||||
init {
|
||||
group = "build"
|
||||
// Defaults
|
||||
link.convention(false)
|
||||
debugSymbols.convention(false)
|
||||
positionIndependentCode.convention(false)
|
||||
sharedLibrary.convention(false)
|
||||
warningFlags.convention(listOf("all", "extra"))
|
||||
warningLevel.convention(3)
|
||||
featureFlags.convention(emptyList())
|
||||
machineFlags.convention(emptyList())
|
||||
compilerArgs.convention(emptyList())
|
||||
defines.convention(emptyMap())
|
||||
libraries.convention(emptyList())
|
||||
linkerFlags.convention(emptyList())
|
||||
frameworks.convention(emptyList())
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun compile() {
|
||||
if (link.get()) {
|
||||
compileAndLink()
|
||||
} else {
|
||||
compileOnly()
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileOnly() {
|
||||
val outputDirectory = outputDir.get().asFile
|
||||
outputDirectory.mkdirs()
|
||||
|
||||
val cFiles = sourceFiles.files.filter { it.extension == "c" }
|
||||
|
||||
if (cFiles.isEmpty()) {
|
||||
logger.info("No C files to compile")
|
||||
return
|
||||
}
|
||||
|
||||
cFiles.forEach { cFile ->
|
||||
when (buildInfo.targetMachine.os) {
|
||||
OS.Linux,
|
||||
OS.MacOS -> compileFileGCC(cFile, outputDirectory)
|
||||
OS.Windows -> compileFileMSVC(cFile, outputDirectory)
|
||||
}
|
||||
}
|
||||
cFiles.forEach { cFile ->
|
||||
val objectFile = outputDirectory.resolve("${cFile.nameWithoutExtension}.o")
|
||||
logger.info("Compiled ${cFile.name} -> ${objectFile.name}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileFileGCC(cFile: java.io.File, outputDirectory: java.io.File) {
|
||||
val objectFile = outputDirectory.resolve("${cFile.nameWithoutExtension}.o")
|
||||
|
||||
val args = buildList {
|
||||
add("cc")
|
||||
add("-c")
|
||||
addAll(buildCompilerFlagsGCC())
|
||||
add(cFile.absolutePath)
|
||||
add("-o")
|
||||
add(objectFile.absolutePath)
|
||||
}
|
||||
|
||||
execOperations.exec {
|
||||
workingDir = project.projectDir
|
||||
commandLine(args)
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileFileMSVC(cFile: java.io.File, outputDirectory: java.io.File) {
|
||||
val objectFile = outputDirectory.resolve("${cFile.nameWithoutExtension}.obj")
|
||||
|
||||
val args = buildList {
|
||||
add("cl.exe")
|
||||
add("/c")
|
||||
addAll(buildCompilerFlagsMSVC())
|
||||
add("/Fo${objectFile.absolutePath}")
|
||||
add(cFile.absolutePath)
|
||||
}
|
||||
|
||||
execOperations.exec {
|
||||
workingDir = project.projectDir
|
||||
commandLine(args)
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileAndLink() {
|
||||
when (buildInfo.targetMachine.os) {
|
||||
OS.Linux,
|
||||
OS.MacOS -> compileAndLinkGCC()
|
||||
OS.Windows -> compileAndLinkMSVC()
|
||||
}
|
||||
|
||||
logger.info("Compiled and linked -> ${outputFile.get().asFile.name}")
|
||||
}
|
||||
|
||||
private fun compileAndLinkGCC() {
|
||||
val output = outputFile.get().asFile
|
||||
|
||||
val args = buildList {
|
||||
add("cc")
|
||||
addAll(buildCompilerFlagsGCC())
|
||||
|
||||
// Add source/object files
|
||||
sourceFiles.files.forEach { file -> add(file.absolutePath) }
|
||||
|
||||
// Library search paths
|
||||
libraryPaths.files.forEach { dir -> add("-L${dir.absolutePath}") }
|
||||
|
||||
// Direct library files. These must come before `-l` libraries below: GNU ld resolves
|
||||
// symbols in a single left-to-right pass, so a static `-lz` etc. must appear after the
|
||||
// archives (e.g. libpkl.a) whose undefined symbols it resolves, or those symbols are
|
||||
// never pulled in.
|
||||
libraryFiles.files.forEach { file -> add(file.absolutePath) }
|
||||
|
||||
// Libraries by name
|
||||
libraries.get().forEach { lib -> add("-l${lib}") }
|
||||
|
||||
// Linker flags
|
||||
if (linkerFlags.get().isNotEmpty()) {
|
||||
add("-Wl,${linkerFlags.get().joinToString(",")}")
|
||||
}
|
||||
|
||||
// macOS frameworks
|
||||
if (buildInfo.os.isMacOS) {
|
||||
frameworks.get().forEach { framework ->
|
||||
add("-framework")
|
||||
add(framework)
|
||||
}
|
||||
}
|
||||
|
||||
if (sharedLibrary.get()) {
|
||||
add("-shared")
|
||||
}
|
||||
|
||||
// Output file
|
||||
add("-o")
|
||||
add(output.absolutePath)
|
||||
}
|
||||
|
||||
output.parentFile.mkdirs()
|
||||
|
||||
execOperations.exec {
|
||||
workingDir = project.projectDir
|
||||
commandLine(args)
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileAndLinkMSVC() {
|
||||
val output = outputFile.get().asFile
|
||||
output.parentFile.mkdirs()
|
||||
|
||||
val args = buildList {
|
||||
add("cl.exe")
|
||||
addAll(buildCompilerFlagsMSVC())
|
||||
|
||||
// Output executable
|
||||
add("/Fe${output.absolutePath}")
|
||||
|
||||
// Add source/object files
|
||||
sourceFiles.files.forEach { file -> add(file.absolutePath) }
|
||||
|
||||
// Linker section
|
||||
if (
|
||||
libraryPaths.files.isNotEmpty() ||
|
||||
libraries.get().isNotEmpty() ||
|
||||
libraryFiles.files.isNotEmpty() ||
|
||||
linkerFlags.get().isNotEmpty()
|
||||
) {
|
||||
add("/link")
|
||||
|
||||
if (sharedLibrary.get()) {
|
||||
add("/DLL")
|
||||
}
|
||||
|
||||
// Library search paths
|
||||
libraryPaths.files.forEach { dir -> add("/LIBPATH:${dir.absolutePath}") }
|
||||
|
||||
// Library files by name
|
||||
libraries.get().forEach { lib -> add("lib${lib}.lib") }
|
||||
|
||||
// Direct library files
|
||||
libraryFiles.files.forEach { file -> add(file.absolutePath) }
|
||||
|
||||
// Additional linker flags
|
||||
addAll(linkerFlags.get())
|
||||
}
|
||||
}
|
||||
|
||||
execOperations.exec {
|
||||
workingDir = project.projectDir
|
||||
commandLine(args)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildCompilerFlagsGCC(): List<String> = buildList {
|
||||
// Warning flags
|
||||
warningFlags.get().forEach { flag -> add("-W${flag}") }
|
||||
|
||||
// Include directories
|
||||
includeDirs.files.forEach { dir -> add("-I${dir.absolutePath}") }
|
||||
|
||||
// Preprocessor definitions
|
||||
defines.get().forEach { (key, value) ->
|
||||
if (value.isEmpty()) {
|
||||
add("-D${key}")
|
||||
} else {
|
||||
add("-D${key}=${value}")
|
||||
}
|
||||
}
|
||||
|
||||
// C standard
|
||||
if (cStandard.isPresent) {
|
||||
add("-std=${cStandard.get()}")
|
||||
}
|
||||
|
||||
// Optimization level
|
||||
if (optimizationLevel.isPresent) {
|
||||
add("-O${optimizationLevel.get()}")
|
||||
}
|
||||
|
||||
// Debug symbols
|
||||
if (debugSymbols.get()) {
|
||||
add("-g")
|
||||
}
|
||||
|
||||
// Position-independent code
|
||||
if (positionIndependentCode.get()) {
|
||||
add("-fPIC")
|
||||
}
|
||||
|
||||
// Feature flags
|
||||
featureFlags.get().forEach { flag -> add("-f${flag}") }
|
||||
|
||||
// Machine flags
|
||||
machineFlags.get().forEach { flag -> add("-m${flag}") }
|
||||
|
||||
// Platform-specific flags
|
||||
if (buildInfo.os.isMacOS && arch.isPresent) {
|
||||
add("-arch")
|
||||
add(arch.get().cCompilerName)
|
||||
}
|
||||
|
||||
// Additional compiler arguments
|
||||
addAll(compilerArgs.get())
|
||||
}
|
||||
|
||||
private fun buildCompilerFlagsMSVC(): List<String> = buildList {
|
||||
// Warning level
|
||||
if (warningLevel.isPresent) {
|
||||
add("/W${warningLevel.get()}")
|
||||
}
|
||||
|
||||
// Include directories
|
||||
includeDirs.files.forEach { dir -> add("/I${dir.absolutePath}") }
|
||||
|
||||
// Preprocessor definitions
|
||||
defines.get().forEach { (key, value) ->
|
||||
if (value.isEmpty()) {
|
||||
add("/D${key}")
|
||||
} else {
|
||||
add("/D${key}=${value}")
|
||||
}
|
||||
}
|
||||
|
||||
// C standard
|
||||
if (cStandard.isPresent) {
|
||||
add("/std:${cStandard.get()}")
|
||||
}
|
||||
|
||||
// Optimization level
|
||||
if (optimizationLevel.isPresent) {
|
||||
when (optimizationLevel.get().lowercase()) {
|
||||
"0",
|
||||
"d" -> add("/Od")
|
||||
"1" -> add("/O1")
|
||||
"2" -> add("/O2")
|
||||
"x",
|
||||
"fast" -> add("/Ox")
|
||||
"s" -> add("/Os")
|
||||
"t" -> add("/Ot")
|
||||
}
|
||||
}
|
||||
|
||||
// Debug symbols
|
||||
if (debugSymbols.get()) {
|
||||
add("/Zi")
|
||||
}
|
||||
|
||||
// Runtime library
|
||||
if (runtimeLibrary.isPresent) {
|
||||
add("/${runtimeLibrary.get()}")
|
||||
}
|
||||
|
||||
// Additional compiler arguments
|
||||
addAll(compilerArgs.get())
|
||||
}
|
||||
}
|
||||
@@ -16,49 +16,64 @@
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.services.BuildService
|
||||
import org.gradle.api.services.BuildServiceParameters
|
||||
import org.gradle.api.tasks.ClasspathNormalizer
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputFiles
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.kotlin.dsl.registerIfAbsent
|
||||
import org.gradle.kotlin.dsl.withNormalizer
|
||||
import org.gradle.process.ExecOperations
|
||||
|
||||
enum class Architecture {
|
||||
AMD64,
|
||||
AARCH64,
|
||||
}
|
||||
|
||||
abstract class NativeImageBuildService : BuildService<BuildServiceParameters.None>
|
||||
|
||||
abstract class NativeImageBuild : DefaultTask() {
|
||||
@get:Input abstract val imageName: Property<String>
|
||||
@get:Input abstract val outputName: Property<String>
|
||||
|
||||
@get:Input abstract val extraNativeImageArgs: ListProperty<String>
|
||||
|
||||
@get:Input abstract val arch: Property<Architecture>
|
||||
@get:Input abstract val arch: Property<Target.Arch>
|
||||
|
||||
@get:Input abstract val mainClass: Property<String>
|
||||
/**
|
||||
* The main class entrypoint for the executable.
|
||||
*
|
||||
* This option is not necessary if [sharedLibrary] is true.
|
||||
*/
|
||||
@get:Optional @get:Input abstract val mainClass: Property<String>
|
||||
|
||||
/** Create a shared library, instead of an executable. */
|
||||
@get:Input abstract val sharedLibrary: Property<Boolean>
|
||||
|
||||
@get:InputFiles abstract val classpath: ConfigurableFileCollection
|
||||
|
||||
private val outputDir = project.layout.buildDirectory.dir("executable")
|
||||
@get:Input abstract val envVars: MapProperty<String, String>
|
||||
|
||||
@get:OutputFile val outputFile = outputDir.flatMap { it.file(imageName) }
|
||||
@get:InputFile @get:Optional abstract val nativeCompilerPath: RegularFileProperty
|
||||
|
||||
@get:Internal abstract val outputDir: DirectoryProperty
|
||||
|
||||
@get:Inject protected abstract val execOperations: ExecOperations
|
||||
|
||||
@get:Inject protected abstract val objectFactory: ObjectFactory
|
||||
|
||||
private val graalVm: Provider<BuildInfo.GraalVm> = arch.map { a ->
|
||||
when (a) {
|
||||
Architecture.AMD64 -> buildInfo.graalVmAmd64
|
||||
Architecture.AARCH64 -> buildInfo.graalVmAarch64
|
||||
Target.Arch.AMD64 -> buildInfo.graalVmAmd64
|
||||
Target.Arch.AARCH64 -> buildInfo.graalVmAarch64
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +103,10 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
// CPU resources).
|
||||
usesService(buildService)
|
||||
|
||||
sharedLibrary.convention(false)
|
||||
|
||||
outputDir.convention(project.layout.buildDirectory.dir("executable"))
|
||||
|
||||
group = "build"
|
||||
|
||||
inputs
|
||||
@@ -98,6 +117,51 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
.files(nativeImageExecutable)
|
||||
.withPropertyName("graalVmNativeImage")
|
||||
.withPathSensitivity(PathSensitivity.ABSOLUTE)
|
||||
if (nativeCompilerPath.isPresent) {
|
||||
inputs.file(nativeCompilerPath)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@OutputFiles
|
||||
fun getEffectiveOutputFiles(): FileCollection {
|
||||
return objectFactory
|
||||
.fileCollection()
|
||||
.from(
|
||||
sharedLibrary.map { isLibrary ->
|
||||
val dir = outputDir.get()
|
||||
val libraryName = outputName.get()
|
||||
// if building a library, native-image outputs the shared library plus four headers
|
||||
// (and, on Windows, an import library); otherwise, it outputs just the one file
|
||||
if (isLibrary) {
|
||||
val sharedLibraryExtension = buildInfo.os.sharedLibraryExtension
|
||||
val staticLibraryExtension = buildInfo.os.staticLibraryExtension
|
||||
dir.files(
|
||||
buildList {
|
||||
add("$libraryName.$sharedLibraryExtension")
|
||||
if (buildInfo.os.isWindows) {
|
||||
// the DLL's import library, which consumers must link against instead of
|
||||
// the .dll itself
|
||||
add("$libraryName.$staticLibraryExtension")
|
||||
// a genuine, self-contained static archive with no runtime DLL dependency,
|
||||
// produced by build_windows.bat
|
||||
add("${libraryName}_s.$staticLibraryExtension")
|
||||
} else {
|
||||
// a genuine, self-contained static archive with no runtime dependency,
|
||||
// produced by build_unix.sh
|
||||
add("$libraryName.$staticLibraryExtension")
|
||||
}
|
||||
add("$libraryName.h")
|
||||
add("${libraryName}_dynamic.h")
|
||||
add("graal_isolate.h")
|
||||
add("graal_isolate_dynamic.h")
|
||||
}
|
||||
)
|
||||
} else {
|
||||
dir.file(libraryName)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
@@ -111,6 +175,7 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
workingDir(outputDir)
|
||||
|
||||
args = buildList {
|
||||
add("--color=always")
|
||||
// must be emitted before any experimental options are used
|
||||
add("-H:+UnlockExperimentalVMOptions")
|
||||
// currently gives a deprecation warning, but we've been told
|
||||
@@ -126,9 +191,14 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
add("-H:IncludeResourceBundles=org.pkl.core.errorMessages")
|
||||
add("-H:IncludeResourceBundles=org.pkl.parser.errorMessages")
|
||||
add("-H:IncludeResources=org/pkl/commons/cli/PklCARoots.pem")
|
||||
add("-H:Class=${mainClass.get()}")
|
||||
if (mainClass.isPresent) {
|
||||
add("-H:Class=${mainClass.get()}")
|
||||
}
|
||||
if (sharedLibrary.get()) {
|
||||
add("--shared")
|
||||
}
|
||||
add("-o")
|
||||
add(imageName.get())
|
||||
add(outputName.get())
|
||||
// the actual limit (currently) used by native-image is this number + 1400 (idea is to
|
||||
// compensate for Truffle's own nodes)
|
||||
add("-H:MaxRuntimeCompileMethods=1800")
|
||||
@@ -138,10 +208,11 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
// disable automatic support for JVM CLI options (puts our main class in full control of
|
||||
// argument parsing)
|
||||
add("-H:-ParseRuntimeOptions")
|
||||
// quick build mode: 40% faster compilation, 20% smaller (but presumably also slower)
|
||||
// executable
|
||||
if (!buildInfo.isReleaseBuild) {
|
||||
add("-Ob")
|
||||
// disable all optimizations
|
||||
add("-O0")
|
||||
// generate debugging information
|
||||
add("-g")
|
||||
}
|
||||
if (buildInfo.isNativeArch) {
|
||||
add("-march=native")
|
||||
@@ -157,8 +228,12 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
// make sure dev machine stays responsive (15% slowdown on my laptop)
|
||||
val processors =
|
||||
Runtime.getRuntime().availableProcessors() /
|
||||
if (buildInfo.os.isMacOsX && !buildInfo.isCiBuild) 4 else 1
|
||||
if (buildInfo.os.isMacOS && !buildInfo.isCiBuild) 4 else 1
|
||||
add("-J-XX:ActiveProcessorCount=${processors}")
|
||||
addAll(envVars.get().entries.map { "-E${it.key}=${it.value}" })
|
||||
if (nativeCompilerPath.isPresent) {
|
||||
add("--native-compiler-path=${nativeCompilerPath.get().asFile}")
|
||||
}
|
||||
// Pass through all `HOMEBREW_` prefixed environment variables to allow build with shimmed
|
||||
// tools.
|
||||
addAll(environment.keys.filter { it.startsWith("HOMEBREW_") }.map { "-E$it" })
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright © 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.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
/**
|
||||
* A build target when building native libraries or executables.
|
||||
*
|
||||
* Pkl only builds for the following listed targets.
|
||||
*/
|
||||
enum class Target(val os: OS, val arch: Arch, val musl: Boolean) {
|
||||
MacosAarch64(os = OS.MacOS, arch = Arch.AARCH64, musl = false),
|
||||
LinuxAarch64(os = OS.Linux, arch = Arch.AARCH64, musl = false),
|
||||
LinuxAmd64(os = OS.Linux, arch = Arch.AMD64, musl = false),
|
||||
AlpineLinuxAmd64(os = OS.Linux, arch = Arch.AMD64, musl = true),
|
||||
WindowsAmd64(os = OS.Windows, arch = Arch.AMD64, musl = false);
|
||||
|
||||
companion object {
|
||||
fun from(os: OS, arch: Arch, musl: Boolean): Target {
|
||||
for (target in entries) {
|
||||
if (target.os == os && target.arch == arch && target.musl == musl) {
|
||||
return target
|
||||
}
|
||||
}
|
||||
throw IllegalArgumentException("Cannot build for $os-$arch with musl: $musl")
|
||||
}
|
||||
}
|
||||
|
||||
val targetName: String
|
||||
get() {
|
||||
return if (musl) {
|
||||
assert(os == OS.Linux)
|
||||
"alpine-linux-$arch"
|
||||
} else "$os-$arch"
|
||||
}
|
||||
|
||||
enum class Arch(
|
||||
/** What we call this arch */
|
||||
val simpleName: String,
|
||||
/** What the C compiler calls this arch */
|
||||
val cCompilerName: String,
|
||||
) {
|
||||
AARCH64("aarch64", "arm64"),
|
||||
AMD64("amd64", "x86_64");
|
||||
|
||||
override fun toString() = simpleName
|
||||
|
||||
companion object {
|
||||
fun fromName(name: String): Arch =
|
||||
when (name) {
|
||||
"aarch64" -> AARCH64
|
||||
"amd64" -> AMD64
|
||||
else -> throw IllegalArgumentException("Unknown arch: $name")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class OS(
|
||||
val simpleName: String,
|
||||
val sharedLibraryExtension: String,
|
||||
val staticLibraryExtension: String,
|
||||
val objectFileExtension: String,
|
||||
val displayName: String,
|
||||
) {
|
||||
MacOS(
|
||||
simpleName = "macos",
|
||||
sharedLibraryExtension = "dylib",
|
||||
staticLibraryExtension = "a",
|
||||
objectFileExtension = "o",
|
||||
displayName = "macOS",
|
||||
),
|
||||
Linux(
|
||||
simpleName = "linux",
|
||||
sharedLibraryExtension = "so",
|
||||
staticLibraryExtension = "a",
|
||||
objectFileExtension = "o",
|
||||
displayName = "Linux",
|
||||
),
|
||||
Windows(
|
||||
simpleName = "windows",
|
||||
sharedLibraryExtension = "dll",
|
||||
staticLibraryExtension = "lib",
|
||||
objectFileExtension = "obj",
|
||||
displayName = "Windows",
|
||||
);
|
||||
|
||||
override fun toString(): String = simpleName
|
||||
|
||||
val isWindows: Boolean
|
||||
get() = this == Windows
|
||||
|
||||
val isMacOS: Boolean
|
||||
get() = this == MacOS
|
||||
|
||||
val isLinux: Boolean
|
||||
get() = this == Linux
|
||||
}
|
||||
}
|
||||
@@ -53,33 +53,40 @@ val nativeImageClasspath =
|
||||
val libs = the<LibrariesForLibs>()
|
||||
|
||||
dependencies {
|
||||
fun executableFile(suffix: String) =
|
||||
fun executableFile(target: Target) =
|
||||
files(
|
||||
layout.buildDirectory.dir("executable").map { dir ->
|
||||
dir.file(executableSpec.name.map { "$it-$suffix" })
|
||||
dir.file(
|
||||
executableSpec.name.map { name ->
|
||||
if (target.os.isWindows) "$name-${target.targetName}.exe"
|
||||
else "$name-${target.targetName}"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
nativeImageClasspath(libs.truffleRuntime)
|
||||
nativeImageClasspath(libs.graalSdk)
|
||||
|
||||
stagedMacAarch64Executable(executableFile("macos-aarch64"))
|
||||
stagedLinuxAmd64Executable(executableFile("linux-amd64"))
|
||||
stagedLinuxAarch64Executable(executableFile("linux-aarch64"))
|
||||
stagedAlpineLinuxAmd64Executable(executableFile("alpine-linux-amd64"))
|
||||
stagedWindowsAmd64Executable(executableFile("windows-amd64.exe"))
|
||||
stagedMacAarch64Executable(executableFile(Target.MacosAarch64))
|
||||
stagedLinuxAarch64Executable(executableFile(Target.LinuxAarch64))
|
||||
stagedLinuxAmd64Executable(executableFile(Target.LinuxAmd64))
|
||||
stagedAlpineLinuxAmd64Executable(executableFile(Target.AlpineLinuxAmd64))
|
||||
stagedWindowsAmd64Executable(executableFile(Target.WindowsAmd64))
|
||||
}
|
||||
|
||||
private fun NativeImageBuild.amd64() {
|
||||
arch = Architecture.AMD64
|
||||
dependsOn(":installGraalVmAmd64")
|
||||
}
|
||||
private fun NativeImageBuild.configure(target: Target) {
|
||||
arch = target.arch
|
||||
|
||||
private fun NativeImageBuild.aarch64() {
|
||||
arch = Architecture.AARCH64
|
||||
dependsOn(":installGraalVmAarch64")
|
||||
}
|
||||
outputName = executableSpec.name.map { "$it-${target.targetName}" }
|
||||
mainClass = executableSpec.mainClass
|
||||
|
||||
if (target.arch == Target.Arch.AARCH64) {
|
||||
dependsOn(":installGraalVmAarch64")
|
||||
} else {
|
||||
dependsOn(":installGraalVmAmd64")
|
||||
}
|
||||
|
||||
private fun NativeImageBuild.setClasspath() {
|
||||
classpath.from(sourceSets.main.map { it.output })
|
||||
classpath.from(
|
||||
project(":pkl-commons-cli").extensions.getByType(SourceSetContainer::class)["svm"].output
|
||||
@@ -88,27 +95,14 @@ private fun NativeImageBuild.setClasspath() {
|
||||
}
|
||||
|
||||
val macExecutableAarch64 =
|
||||
tasks.register<NativeImageBuild>("macExecutableAarch64") {
|
||||
imageName = executableSpec.name.map { "$it-macos-aarch64" }
|
||||
mainClass = executableSpec.mainClass
|
||||
aarch64()
|
||||
setClasspath()
|
||||
}
|
||||
tasks.register<NativeImageBuild>("macExecutableAarch64") { configure(Target.MacosAarch64) }
|
||||
|
||||
val linuxExecutableAmd64 =
|
||||
tasks.register<NativeImageBuild>("linuxExecutableAmd64") {
|
||||
imageName = executableSpec.name.map { "$it-linux-amd64" }
|
||||
mainClass = executableSpec.mainClass
|
||||
amd64()
|
||||
setClasspath()
|
||||
}
|
||||
tasks.register<NativeImageBuild>("linuxExecutableAmd64") { configure(Target.LinuxAmd64) }
|
||||
|
||||
val linuxExecutableAarch64 =
|
||||
tasks.register<NativeImageBuild>("linuxExecutableAarch64") {
|
||||
imageName = executableSpec.name.map { "$it-linux-aarch64" }
|
||||
mainClass = executableSpec.mainClass
|
||||
aarch64()
|
||||
setClasspath()
|
||||
configure(Target.LinuxAarch64)
|
||||
// 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")
|
||||
@@ -116,19 +110,14 @@ val linuxExecutableAarch64 =
|
||||
|
||||
val alpineExecutableAmd64 =
|
||||
tasks.register<NativeImageBuild>("alpineExecutableAmd64") {
|
||||
imageName = executableSpec.name.map { "$it-alpine-linux-amd64" }
|
||||
mainClass = executableSpec.mainClass
|
||||
amd64()
|
||||
setClasspath()
|
||||
extraNativeImageArgs.addAll(listOf("--static", "--libc=musl"))
|
||||
configure(Target.AlpineLinuxAmd64)
|
||||
extraNativeImageArgs.addAll("--static", "--libc=musl")
|
||||
}
|
||||
|
||||
val windowsExecutableAmd64 =
|
||||
tasks.register<NativeImageBuild>("windowsExecutableAmd64") {
|
||||
imageName = executableSpec.name.map { "$it-windows-amd64" }
|
||||
mainClass = executableSpec.mainClass
|
||||
amd64()
|
||||
setClasspath()
|
||||
configure(Target.WindowsAmd64)
|
||||
extraNativeImageArgs.add("-Dfile.encoding=UTF-8")
|
||||
}
|
||||
|
||||
val assembleNative = tasks.named("assembleNative")
|
||||
@@ -216,93 +205,51 @@ val assembleNativeAlpineLinuxAmd64 =
|
||||
val assembleNativeWindowsAmd64 =
|
||||
tasks.named("assembleNativeWindowsAmd64") { wraps(windowsExecutableAmd64) }
|
||||
|
||||
private fun MavenPublication.configurePublication(target: Target, configuration: Configuration) {
|
||||
artifactId = "${executableSpec.publicationName.get()}-${target.targetName}"
|
||||
pom {
|
||||
name = "${executableSpec.publicationName.get()}-${target.targetName}"
|
||||
url = executableSpec.website
|
||||
artifact(configuration.singleFile) {
|
||||
classifier = null
|
||||
extension = if (target.os.isWindows) "exe" else "bin"
|
||||
builtBy(configuration)
|
||||
}
|
||||
description =
|
||||
executableSpec.documentationName.map { name ->
|
||||
buildString {
|
||||
append("Native $name executable for ${target.os.displayName}/${target.arch}")
|
||||
if (target.musl) {
|
||||
append(" and statically linked to musl")
|
||||
}
|
||||
append(".")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
// need to put in `afterEvaluate` because `artifactId` cannot be set lazily.
|
||||
project.afterEvaluate {
|
||||
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."
|
||||
}
|
||||
}
|
||||
configurePublication(Target.MacosAarch64, stagedMacAarch64Executable)
|
||||
}
|
||||
|
||||
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."
|
||||
}
|
||||
}
|
||||
configurePublication(Target.LinuxAmd64, stagedLinuxAmd64Executable)
|
||||
}
|
||||
|
||||
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."
|
||||
}
|
||||
}
|
||||
configurePublication(Target.LinuxAarch64, stagedLinuxAarch64Executable)
|
||||
}
|
||||
|
||||
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."
|
||||
}
|
||||
}
|
||||
configurePublication(Target.AlpineLinuxAmd64, stagedAlpineLinuxAmd64Executable)
|
||||
}
|
||||
|
||||
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."
|
||||
}
|
||||
}
|
||||
configurePublication(Target.WindowsAmd64, stagedWindowsAmd64Executable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,31 +46,20 @@ val assembleNative =
|
||||
tasks.register("assembleNative") {
|
||||
group = "build"
|
||||
|
||||
@Suppress("DuplicatedCode")
|
||||
if (!buildInfo.isCrossArchSupported && buildInfo.isCrossArch) {
|
||||
throw GradleException("Cross-arch builds are not supported on ${buildInfo.os.name}")
|
||||
doLast {
|
||||
throw GradleException("Cross-arch builds are not supported on ${buildInfo.os.name}")
|
||||
}
|
||||
}
|
||||
|
||||
when {
|
||||
buildInfo.os.isMacOsX && buildInfo.targetArch == "aarch64" -> {
|
||||
wraps(assembleNativeMacOsAarch64)
|
||||
}
|
||||
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}"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Suppress("DuplicatedCode")
|
||||
when (buildInfo.targetMachine) {
|
||||
Target.MacosAarch64 -> wraps(assembleNativeMacOsAarch64)
|
||||
Target.LinuxAarch64 -> wraps(assembleNativeLinuxAarch64)
|
||||
Target.LinuxAmd64 -> wraps(assembleNativeLinuxAmd64)
|
||||
Target.AlpineLinuxAmd64 -> wraps(assembleNativeAlpineLinuxAmd64)
|
||||
Target.WindowsAmd64 -> wraps(assembleNativeWindowsAmd64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,31 +68,18 @@ val testNative =
|
||||
group = "verification"
|
||||
dependsOn(assembleNative)
|
||||
|
||||
@Suppress("DuplicatedCode")
|
||||
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.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}"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Suppress("DuplicatedCode")
|
||||
when (buildInfo.targetMachine) {
|
||||
Target.MacosAarch64 -> wraps(testNativeMacOsAarch64)
|
||||
Target.LinuxAarch64 -> wraps(testNativeLinuxAarch64)
|
||||
Target.LinuxAmd64 -> wraps(testNativeLinuxAmd64)
|
||||
Target.AlpineLinuxAmd64 -> wraps(testNativeAlpineLinuxAmd64)
|
||||
Target.WindowsAmd64 -> wraps(testNativeWindowsAmd64)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
::===----------------------------------------------------------------------===//
|
||||
:: Copyright © $YEAR 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.
|
||||
::===----------------------------------------------------------------------===//
|
||||
@@ -0,0 +1,15 @@
|
||||
#===----------------------------------------------------------------------===//
|
||||
# Copyright © $YEAR 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.
|
||||
#===----------------------------------------------------------------------===//
|
||||
Reference in New Issue
Block a user