From f6107b6e860ec3349b5b0515041b590753ba2634 Mon Sep 17 00:00:00 2001 From: Daniel Chao Date: Tue, 28 Jul 2026 16:32:19 -0700 Subject: [PATCH] Fix libpkl and windows builds (#1799) * Fix issue where linker can't find object files * Fix issue where macOS libpkl builds time out due to exhausting host resources --- .../src/main/kotlin/NativeImageBuild.kt | 27 ++++++++++++++++++- libpkl/libpkl.gradle.kts | 23 +++++++++++----- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/build-logic/src/main/kotlin/NativeImageBuild.kt b/build-logic/src/main/kotlin/NativeImageBuild.kt index 11505b969..ed31555b0 100644 --- a/build-logic/src/main/kotlin/NativeImageBuild.kt +++ b/build-logic/src/main/kotlin/NativeImageBuild.kt @@ -29,6 +29,7 @@ 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.provider.SetProperty import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters import org.gradle.api.tasks.ClasspathNormalizer @@ -37,6 +38,7 @@ import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.OutputDirectories import org.gradle.api.tasks.OutputFiles import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction @@ -53,6 +55,12 @@ abstract class NativeImageBuild : DefaultTask() { @get:Input abstract val arch: Property + /** + * Names of extra directories, relative to the native-image working directory, that should be + * copied into [outputDir] after a successful build. + */ + @get:Input abstract val additionalOutputDirectoryNames: SetProperty + /** * The main class entrypoint for the executable. * @@ -163,12 +171,20 @@ abstract class NativeImageBuild : DefaultTask() { } ) } else { - dir.file(libraryName) + val executableName = if (buildInfo.os.isWindows) "${libraryName}.exe" else libraryName + dir.file(executableName) } } ) } + @Suppress("unused") + @OutputDirectories + fun getEffectiveOutputDirectories(): FileCollection = + objectFactory + .fileCollection() + .from(additionalOutputDirectoryNames.map { names -> names.map { outputDir.get().dir(it) } }) + @TaskAction protected fun run() { val workingDir = @@ -263,6 +279,15 @@ abstract class NativeImageBuild : DefaultTask() { } Files.copy(sourceFile, targetFile, StandardCopyOption.REPLACE_EXISTING) } + for (dirName in additionalOutputDirectoryNames.get()) { + val sourceDir = workingDir.resolve(dirName).toFile() + if (!sourceDir.exists()) { + throw GradleException("Expected to find directory $dirName in the working dir but didn't") + } + val targetDir = outputDir.get().asFile.resolve(dirName) + targetDir.deleteRecursively() + sourceDir.copyRecursively(targetDir, overwrite = true) + } } } } diff --git a/libpkl/libpkl.gradle.kts b/libpkl/libpkl.gradle.kts index d42954206..949f63f76 100644 --- a/libpkl/libpkl.gradle.kts +++ b/libpkl/libpkl.gradle.kts @@ -91,18 +91,29 @@ private fun NativeImageBuild.configure(target: Target) { sharedLibrary = true val scriptName = if (buildInfo.os.isWindows) "build_windows.bat" else "build_unix.sh" nativeCompilerPath = projectDir.resolve("scripts/${scriptName}") + + if (!buildInfo.os.isWindows) { + // build_unix.sh extracts the object files of every archive it links against into a loose + // `objects/` dir so that `buildStaticLibrary` can merge them into a single, self-contained + // static library. + // + // Don't need to do this for Windows because it produces a merged archive. + additionalOutputDirectoryNames.add("objects") + } } val macNativeImageAarch64 = tasks.register("macNativeImageAarch64") { configure(Target.MacosAarch64) // macOS only supports 16K page size - extraNativeImageArgs = - listOf( - "-H:PageSize=16384", - // increase memory available to native-image - "-J-Xmx32g", - ) + extraNativeImageArgs = buildList { + add("-H:PageSize=16384") + if (buildInfo.isCiBuild) { + add("-J-Xmx12g") + add("-H:+DeadlockWatchdogExitOnTimeout") + add("-H:DeadlockWatchdogInterval=10") + } + } } val linuxNativeImageAmd64 =